Skip to content

[6.0] [Completion] Completions for inout, borrowing, consuming, isolated, consume, and copy #74526

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
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
4 changes: 2 additions & 2 deletions include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -453,10 +453,10 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(_local, KnownToBeLocal,
DeclModifier | OnFunc | OnParam | OnVar | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
130)
CONTEXTUAL_SIMPLE_DECL_ATTR(consuming, Consuming,
OnFunc | OnAccessor | DeclModifier | UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
OnFunc | OnAccessor | DeclModifier | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
140)
CONTEXTUAL_SIMPLE_DECL_ATTR(borrowing, Borrowing,
OnFunc | OnAccessor | DeclModifier | UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
OnFunc | OnAccessor | DeclModifier | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
141)
DECL_ATTR(attached, MacroRole,
OnMacro | AllowMultipleAttributes | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ DECL_KEYWORD(extension)
DECL_KEYWORD(func)
DECL_KEYWORD(import)
DECL_KEYWORD(init)
DECL_KEYWORD(inout)
DECL_KEYWORD(let)
DECL_KEYWORD(operator)
DECL_KEYWORD(precedencegroup)
Expand Down Expand Up @@ -259,8 +258,9 @@ MISC(string_interpolation_anchor)
MISC(kw_yield)
MISC(kw_discard)
MISC(kw_then)
SWIFT_KEYWORD(inout)

// The following tokens are irrelevant for swiftSyntax and thus only declared
// The following tokens are irrelevant for swiftSyntax and thus only declared
// in this .def file

SIL_KEYWORD(undef)
Expand Down
1 change: 1 addition & 0 deletions include/swift/IDE/CodeCompletionResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ enum class CompletionKind : uint8_t {
PostfixExpr,
KeyPathExprObjC,
KeyPathExprSwift,
TypePossibleFunctionParamBeginning,
TypeDeclResultBeginning,
TypeBeginning,
TypeSimpleOrComposition,
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Parse/IDEInspectionCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ class CodeCompletionCallbacks {
/// #keyPath argument have been parsed yet.
virtual void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) {};

/// Complete the beginning of the type for a parameter of a
/// func/subscript/closure, or the type for a parameter in a function type.
/// For the latter, we cannot know for sure whether the user is trying to
/// write a function type, so will complete for e.g `let x: (#^COMPLETE^#`.
virtual void completeTypePossibleFunctionParamBeginning() {}

/// Complete the beginning of the type of result of func/var/let/subscript.
virtual void completeTypeDeclResultBeginning() {};

Expand Down
16 changes: 16 additions & 0 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace) override;
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override;

void completeTypePossibleFunctionParamBeginning() override;
void completeTypeDeclResultBeginning() override;
void completeTypeBeginning() override;
void completeTypeSimpleOrComposition() override;
Expand Down Expand Up @@ -430,6 +431,11 @@ void CodeCompletionCallbacksImpl::completePoundAvailablePlatform() {
CurDeclContext = P.CurDeclContext;
}

void CodeCompletionCallbacksImpl::completeTypePossibleFunctionParamBeginning() {
Kind = CompletionKind::TypePossibleFunctionParamBeginning;
CurDeclContext = P.CurDeclContext;
}

void CodeCompletionCallbacksImpl::completeTypeDeclResultBeginning() {
Kind = CompletionKind::TypeDeclResultBeginning;
CurDeclContext = P.CurDeclContext;
Expand Down Expand Up @@ -899,6 +905,8 @@ void swift::ide::addExprKeywords(CodeCompletionResultSink &Sink,
addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try, "", flair);
addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try, "", flair);
addKeyword(Sink, "await", CodeCompletionKeywordKind::None, "", flair);
addKeyword(Sink, "consume", CodeCompletionKeywordKind::None, "", flair);
addKeyword(Sink, "copy", CodeCompletionKeywordKind::None, "", flair);
}

void swift::ide::addSuperKeyword(CodeCompletionResultSink &Sink,
Expand Down Expand Up @@ -1058,6 +1066,12 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
}
break;

case CompletionKind::TypePossibleFunctionParamBeginning:
addKeyword(Sink, "inout", CodeCompletionKeywordKind::kw_inout);
addKeyword(Sink, "borrowing", CodeCompletionKeywordKind::None);
addKeyword(Sink, "consuming", CodeCompletionKeywordKind::None);
addKeyword(Sink, "isolated", CodeCompletionKeywordKind::None);
LLVM_FALLTHROUGH;
case CompletionKind::TypeBeginning:
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
LLVM_FALLTHROUGH;
Expand Down Expand Up @@ -1262,6 +1276,7 @@ void swift::ide::postProcessCompletionResults(
// names at non-type name position are "rare".
if (result->getKind() == CodeCompletionResultKind::Declaration &&
result->getAssociatedDeclKind() == CodeCompletionDeclKind::Protocol &&
Kind != CompletionKind::TypePossibleFunctionParamBeginning &&
Kind != CompletionKind::TypeBeginning &&
Kind != CompletionKind::TypeSimpleOrComposition &&
Kind != CompletionKind::TypeSimpleBeginning &&
Expand Down Expand Up @@ -1755,6 +1770,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
break;
}

case CompletionKind::TypePossibleFunctionParamBeginning:
case CompletionKind::TypeDeclResultBeginning:
case CompletionKind::TypeBeginning:
case CompletionKind::TypeSimpleOrComposition:
Expand Down
22 changes: 19 additions & 3 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,22 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
}

auto parseParamType = [&]() -> ParserResult<TypeRepr> {
// 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);
}
return parseType(diag::expected_parameter_type);
};

if (startsParameterName(isClosure)) {
// identifier-or-none for the first name
param.FirstNameLoc = consumeArgumentLabel(param.FirstName,
Expand Down Expand Up @@ -421,7 +437,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// (':' type)?
if (consumeIf(tok::colon)) {

auto type = parseType(diag::expected_parameter_type);
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();

Expand All @@ -444,7 +460,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
}

if (isBareType && paramContext == ParameterContextKind::EnumElement) {
auto type = parseType(diag::expected_parameter_type);
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
param.FirstName = Identifier();
Expand All @@ -459,7 +475,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// the user is about to type the parameter label and we shouldn't
// suggest types.
SourceLoc typeStartLoc = Tok.getLoc();
auto type = parseType(diag::expected_parameter_type);
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();

Expand Down
10 changes: 10 additions & 0 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,16 @@ 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();
return makeParserCodeCompletionStatus();
}

// Parse the type annotation.
auto type = parseType(diag::expected_type);
if (type.hasCodeCompletion())
Expand Down
2 changes: 0 additions & 2 deletions test/IDE/complete_at_top_level_library.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ protocol MyProtocol {}
// LIBRARY-DAG: Keyword[func]/None: func; name=func
// LIBRARY-DAG: Keyword[import]/None: import; name=import
// LIBRARY-DAG: Keyword[init]/None: init; name=init
// LIBRARY-DAG: Keyword[inout]/None: inout; name=inout
// LIBRARY-DAG: Keyword[operator]/None: operator; name=operator
// LIBRARY-DAG: Keyword[precedencegroup]/None: precedencegroup; name=precedencegroup
// LIBRARY-DAG: Keyword[protocol]/None/Flair[CommonKeyword]: protocol; name=protocol
Expand Down Expand Up @@ -86,7 +85,6 @@ protocol MyProtocol {}
// SCRIPT-DAG: Keyword[func]/None: func; name=func
// SCRIPT-DAG: Keyword[import]/None: import; name=import
// SCRIPT-DAG: Keyword[init]/None: init; name=init
// SCRIPT-DAG: Keyword[inout]/None: inout; name=inout
// SCRIPT-DAG: Keyword[operator]/None: operator; name=operator
// SCRIPT-DAG: Keyword[precedencegroup]/None: precedencegroup; name=precedencegroup
// SCRIPT-DAG: Keyword[protocol]/None: protocol; name=protocol
Expand Down
31 changes: 26 additions & 5 deletions test/IDE/complete_keywords.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// KW_IN: Keyword[in]/None: in{{; name=.+$}}
// KW_NO_IN-NOT: Keyword[in]

// KW_NO_INOUT-NOT: Keyword[inout]

// KW_DECL-DAG: Keyword[class]/None: class{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: actor{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: convenience{{; name=.+$}}
Expand All @@ -23,6 +25,8 @@
// KW_DECL-DAG: Keyword[let]/None: let{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: mutating{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: nonmutating{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: consuming{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: borrowing{{; name=.+$}}
// KW_DECL-DAG: Keyword[operator]/None: operator{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: optional{{; name=.+$}}
// KW_DECL-DAG: Keyword/None: override{{; name=.+$}}
Expand Down Expand Up @@ -58,6 +62,8 @@
// KW_DECL_PROTOCOL-DAG: Keyword[let]/None: let{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: mutating{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: nonmutating{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: consuming{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: borrowing{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword[operator]/None/Flair[RareKeyword]: operator{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: optional{{; name=.+$}}
// KW_DECL_PROTOCOL-DAG: Keyword/None: override{{; name=.+$}}
Expand Down Expand Up @@ -93,6 +99,8 @@
// KW_DECL_TYPECONTEXT-DAG: Keyword[let]/None: let{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: mutating{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: nonmutating{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: consuming{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: borrowing{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword[operator]/None/Flair[RareKeyword]: operator{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: optional{{; name=.+$}}
// KW_DECL_TYPECONTEXT-DAG: Keyword/None: override{{; name=.+$}}
Expand Down Expand Up @@ -132,6 +140,8 @@
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[let]/None: let{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: mutating{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: nonmutating{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: consuming{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: borrowing{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[operator]/None: operator{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: optional{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: override{{; name=.+$}}
Expand Down Expand Up @@ -172,6 +182,9 @@
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[try]/None: try{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[try]/None: try!{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[try]/None: try?{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: await{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: consume{{; name=.+$}}
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword/None: copy{{; name=.+$}}
//
// Literals
//
Expand All @@ -198,6 +211,8 @@
// KW_DECL_STMT-DAG: Keyword[let]/None: let{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: mutating{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: nonmutating{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: consuming{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: borrowing{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword[operator]/None/Flair[RareKeyword]: operator{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None/Flair[RareKeyword]: optional{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None/Flair[RareKeyword]: override{{; name=.+$}}
Expand Down Expand Up @@ -238,6 +253,9 @@
// KW_DECL_STMT-DAG: Keyword[try]/None: try{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword[try]/None: try!{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword[try]/None: try?{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: await{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: consume{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: copy{{; name=.+$}}
//
// Literals
//
Expand All @@ -252,6 +270,9 @@
// KW_EXPR-DAG: Keyword[try]/None: try{{; name=.+$}}
// KW_EXPR-DAG: Keyword[try]/None: try!{{; name=.+$}}
// KW_EXPR-DAG: Keyword[try]/None: try?{{; name=.+$}}
// KW_EXPR-DAG: Keyword/None: await{{; name=.+$}}
// KW_EXPR-DAG: Keyword/None: consume{{; name=.+$}}
// KW_EXPR-DAG: Keyword/None: copy{{; name=.+$}}
//
// let and var
//
Expand Down Expand Up @@ -283,7 +304,7 @@
// KW_EXPR_NEG-NOT: Keyword{{.*}}catch
// KW_EXPR_NEG-NOT: Keyword{{.*}}break

#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN;check=KW_NO_INOUT^#

for _ in 1...10 {
#^TOP_LEVEL_2?check=KW_DECL_STMT;check=KW_NO_RETURN;check=KW_NO_IN^#
Expand Down Expand Up @@ -357,19 +378,19 @@ struct InInit {
}

struct InStruct {
#^IN_NOMINAL_DECL_1?check=KW_DECL_TYPECONTEXT^#
#^IN_NOMINAL_DECL_1?check=KW_DECL_TYPECONTEXT;check=KW_NO_INOUT^#
}

enum InEnum {
#^IN_NOMINAL_DECL_2?check=KW_DECL_TYPECONTEXT^#
#^IN_NOMINAL_DECL_2?check=KW_DECL_TYPECONTEXT;check=KW_NO_INOUT^#
}

class InClass {
#^IN_NOMINAL_DECL_3?check=KW_DECL_TYPECONTEXT^#
#^IN_NOMINAL_DECL_3?check=KW_DECL_TYPECONTEXT;check=KW_NO_INOUT^#
}

protocol InProtocol {
#^IN_NOMINAL_DECL_4?check=KW_DECL_PROTOCOL^#
#^IN_NOMINAL_DECL_4?check=KW_DECL_PROTOCOL;check=KW_NO_INOUT^#
}

struct AfterOtherKeywords1 {
Expand Down
34 changes: 34 additions & 0 deletions test/IDE/complete_ownership_specifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %batch-code-completion

func foo(x: #^FUNC_PARAM?check=SPECIFIER^#) {
let fn1 = { (x: #CLOSURE_PARAM?check=SPECIFIER#) in }
let fn2: (#^CLOSURE_PARAM_TY_COMPLETE?check=SPECIFIER^#) -> Void
let fn3: (#^CLOSURE_PARAM_TY_INCOMPLETE?check=SPECIFIER^#
}

struct S {
init(x: #^INIT_PARAM?check=SPECIFIER^#) {}
subscript(x: #SUBSCRIPT_PARAM?check=SPECIFIER#) {}
}

// 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 for a regular variable type.
let x: #^VAR_TY?check=SPECIFIER_NOT^#

// Or for a return type.
func bar() -> #^RETURN_TY?check=SPECIFIER_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_NOT-NOT: Keyword[inout]/None: inout
// SPECIFIER_NOT-NOT: Keyword/None: consuming
// SPECIFIER_NOT-NOT: Keyword/None: borrowing
// SPECIFIER_NOT-NOT: Keyword/None: isolated
2 changes: 2 additions & 0 deletions tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ bool SourceKit::CodeCompletion::addCustomCompletions(
addCompletion(custom);
}
break;
case CompletionKind::TypePossibleFunctionParamBeginning:
case CompletionKind::TypeDeclResultBeginning:
case CompletionKind::TypeBeginning:
case CompletionKind::TypeSimpleOrComposition:
Expand Down Expand Up @@ -452,6 +453,7 @@ void CodeCompletionOrganizer::Impl::addCompletionsWithFilter(
if (filterText.empty()) {
bool hideLowPriority =
options.hideLowPriority &&
completionKind != CompletionKind::TypePossibleFunctionParamBeginning &&
completionKind != CompletionKind::TypeDeclResultBeginning &&
completionKind != CompletionKind::TypeBeginning &&
completionKind != CompletionKind::TypeSimpleOrComposition &&
Expand Down