Skip to content

[Completion] Add completion for sending specifier #74633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,7 @@ class Parser {
if (next.isAny(tok::at_sign, tok::kw_inout, tok::l_paren,
tok::identifier, tok::l_square, tok::kw_Any,
tok::kw_Self, tok::kw__, tok::kw_var,
tok::kw_let))
tok::kw_let, tok::code_complete))
return true;

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

/// Attempts to perform code completion for the possible start of a function
/// parameter type, returning the source location of the consumed completion
/// token, or a null location if there is no completion token.
SourceLoc tryCompleteFunctionParamTypeBeginning();

/// Parse a parameter-clause.
///
/// \verbatim
Expand Down
8 changes: 6 additions & 2 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1073,10 +1073,14 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
addKeyword(Sink, "consuming", CodeCompletionKeywordKind::None);
addKeyword(Sink, "isolated", CodeCompletionKeywordKind::None);
LLVM_FALLTHROUGH;
case CompletionKind::TypeDeclResultBeginning:
addKeyword(Sink, "sending", CodeCompletionKeywordKind::None);
LLVM_FALLTHROUGH;
case CompletionKind::TypeBeginning:
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
// Not technically allowed after '->', since you need to write in parens.
if (Kind != CompletionKind::TypeDeclResultBeginning)
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
LLVM_FALLTHROUGH;
case CompletionKind::TypeDeclResultBeginning:
case CompletionKind::TypeSimpleOrComposition:
addKeyword(Sink, "some", CodeCompletionKeywordKind::None);
addKeyword(Sink, "any", CodeCompletionKeywordKind::None);
Expand Down
34 changes: 26 additions & 8 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,27 @@ bool Parser::startsParameterName(bool isClosure) {
return isClosure;
}

SourceLoc Parser::tryCompleteFunctionParamTypeBeginning() {
if (!L->isCodeCompletion())
return SourceLoc();

// Skip over any starting parameter specifiers.
{
CancellableBacktrackingScope backtrack(*this);
ParsedTypeAttributeList attrs;
attrs.parse(*this);
if (!Tok.is(tok::code_complete))
return SourceLoc();

backtrack.cancelBacktrack();
}

if (CodeCompletionCallbacks)
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();

return consumeToken(tok::code_complete);
}

ParserStatus
Parser::parseParameterClause(SourceLoc &leftParenLoc,
SmallVectorImpl<ParsedParameter> &params,
Expand Down Expand Up @@ -360,14 +381,11 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// Currently none of the parameter type completions are relevant for
// enum cases, so don't include them. We'll complete for a regular type
// beginning instead.
if (Tok.is(tok::code_complete) &&
paramContext != ParameterContextKind::EnumElement) {
if (CodeCompletionCallbacks)
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();

auto CCLoc = consumeToken(tok::code_complete);
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
if (paramContext != ParameterContextKind::EnumElement) {
if (auto CCLoc = tryCompleteFunctionParamTypeBeginning()) {
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
}
}
return parseType(diag::expected_parameter_type);
};
Expand Down
11 changes: 3 additions & 8 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,15 +1203,10 @@ ParserResult<TypeRepr> Parser::parseTypeTupleBody() {
}
Backtracking.reset();

// If we have a code completion token, treat this as a possible parameter
// type since the user may be writing this as a function type.
if (Tok.is(tok::code_complete)) {
if (CodeCompletionCallbacks)
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();

consumeToken();
// Try complete the start of a parameter type since the user may be writing
// this as a function type.
if (tryCompleteFunctionParamTypeBeginning())
return makeParserCodeCompletionStatus();
}

// Parse the type annotation.
auto type = parseType(diag::expected_type);
Expand Down
34 changes: 0 additions & 34 deletions test/IDE/complete_ownership_specifier.swift

This file was deleted.

53 changes: 53 additions & 0 deletions test/IDE/complete_param_specifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// RUN: %batch-code-completion

func foo(x: #^FUNC_PARAM?check=SPECIFIER^#) {
let fn1 = { (x: #CLOSURE_PARAM?check=SPECIFIER#) in }
let fn2 = { (x: consuming #CLOSURE_PARAM2?check=SPECIFIER#) in }
let fn3: (#^CLOSURE_PARAM_TY_COMPLETE?check=SPECIFIER^#) -> Void
let fn4: (borrowing #^CLOSURE_PARAM_TY_COMPLETE2?check=SPECIFIER^#) -> Void
let fn5: (#^CLOSURE_PARAM_TY_INCOMPLETE?check=SPECIFIER^#
let fn6: (inout #^CLOSURE_PARAM_TY_INCOMPLETE2?check=SPECIFIER^#
}

func bar(_ x: borrowing #^FUNC_PARAM_2?check=SPECIFIER^#) {}

struct S {
init(x: #^INIT_PARAM?check=SPECIFIER^#) {}
subscript(x: #SUBSCRIPT_PARAM?check=SPECIFIER#) -> #^SUBSCRIPT_RET?check=RESULT;check=RESULT_NOT^# {}
}

// Don't complete for enum cases.
enum E {
case e(#^ENUM_CASE_TY?check=SPECIFIER_NOT^#)
case f(x: #^ENUM_CASE_LABELED_TY?check=SPECIFIER_NOT^#)
}

// Don't complete the parameter specifiers for a variable type.
//
// Note that we will still complete 'sending' here, even though it isn't
// currently supported for computed properties (it is supported for functions
// and subscripts though).
let x: #^VAR_TY?check=RESULT;check=RESULT_NOT^#
var y: #^VAR_TY2?check=RESULT;check=RESULT_NOT^#

// Or for a return type.
func bar() -> #^RESULT_TY?check=RESULT;check=RESULT_NOT^# {}

// SPECIFIER-DAG: Keyword[inout]/None: inout; name=inout
// SPECIFIER-DAG: Keyword/None: consuming; name=consuming
// SPECIFIER-DAG: Keyword/None: borrowing; name=borrowing
// SPECIFIER-DAG: Keyword/None: isolated; name=isolated
// SPECIFIER-DAG: Keyword/None: sending; name=sending

// SPECIFIER_NOT-NOT: Keyword[inout]/None: inout
// SPECIFIER_NOT-NOT: Keyword/None: consuming
// SPECIFIER_NOT-NOT: Keyword/None: borrowing
// SPECIFIER_NOT-NOT: Keyword/None: isolated
// SPECIFIER_NOT-NOT: Keyword/None: sending

// RESULT_NOT-NOT: Keyword[inout]/None: inout
// RESULT_NOT-NOT: Keyword/None: consuming
// RESULT_NOT-NOT: Keyword/None: borrowing
// RESULT_NOT-NOT: Keyword/None: isolated

// RESULT-DAG: Keyword/None: sending