Skip to content

[6.0] [Completion] Update type attribute completions #74989

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 5 commits into from
Jul 6, 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
4 changes: 4 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,10 @@ class alignas(1 << AttrAlignInBits) TypeAttribute
/// Return the name (like "autoclosure") for an attribute ID.
static const char *getAttrName(TypeAttrKind kind);

/// Returns whether the given attribute is considered "user inaccessible",
/// which affects e.g whether it shows up in code completion.
static bool isUserInaccessible(TypeAttrKind DK);

static TypeAttribute *createSimple(const ASTContext &context,
TypeAttrKind kind,
SourceLoc atLoc,
Expand Down
6 changes: 3 additions & 3 deletions include/swift/AST/TypeAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,9 @@
// Type attributes
SIMPLE_TYPE_ATTR(autoclosure, Autoclosure)
TYPE_ATTR(convention, Convention)
SIMPLE_TYPE_ATTR(noescape, NoEscape)
SIMPLE_TYPE_ATTR(escaping, Escaping)
TYPE_ATTR(differentiable, Differentiable)
SIMPLE_TYPE_ATTR(noDerivative, NoDerivative)
SIMPLE_TYPE_ATTR(async, Async)
SIMPLE_TYPE_ATTR(Sendable, Sendable)
SIMPLE_TYPE_ATTR(retroactive, Retroactive)
SIMPLE_TYPE_ATTR(unchecked, Unchecked)
Expand All @@ -68,10 +66,11 @@ TYPE_ATTR(_opaqueReturnTypeOf, OpaqueReturnTypeOf)
TYPE_ATTR(isolated, Isolated)

// SIL-specific attributes
SIMPLE_SIL_TYPE_ATTR(async, Async)
SIMPLE_SIL_TYPE_ATTR(block_storage, BlockStorage)
SIMPLE_SIL_TYPE_ATTR(box, Box)
SIMPLE_SIL_TYPE_ATTR(dynamic_self, DynamicSelf)
#define REF_STORAGE(Name, name, ...) SIMPLE_TYPE_ATTR(sil_##name, SIL##Name)
#define REF_STORAGE(Name, name, ...) SIMPLE_SIL_TYPE_ATTR(sil_##name, SIL##Name)
#include "swift/AST/ReferenceStorage.def"
SIMPLE_SIL_TYPE_ATTR(error, Error)
SIMPLE_SIL_TYPE_ATTR(error_indirect, ErrorIndirect)
Expand All @@ -83,6 +82,7 @@ SIMPLE_SIL_TYPE_ATTR(inout, Inout)
SIMPLE_SIL_TYPE_ATTR(inout_aliasable, InoutAliasable)
SIMPLE_SIL_TYPE_ATTR(in_guaranteed, InGuaranteed)
SIMPLE_SIL_TYPE_ATTR(in_constant, InConstant)
SIMPLE_SIL_TYPE_ATTR(noescape, NoEscape)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjmccall I don't suppose you remember why we didn't make noescape (and async) a SIMPLE_SIL_TYPE_ATTR in 41cdfb0? Mostly asking in terms of risk here - we could instead leave this change out of 6.0 and just add the missing completions in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally didn't put any effort in that patch into recategorizing the existing attributes. I wanted it to be focused on the high-level representation change.

I don't know why they're not simple attributes in SIL. They certainly look like simple attributes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good, was just checking that there wasn't any underlying reason that we missed. Thanks!

SIMPLE_SIL_TYPE_ATTR(pack_owned, PackOwned)
SIMPLE_SIL_TYPE_ATTR(pack_guaranteed, PackGuaranteed)
SIMPLE_SIL_TYPE_ATTR(pack_inout, PackInout)
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 @@ -229,6 +229,7 @@ enum class CompletionKind : uint8_t {
StmtLabel,
ForEachPatternBeginning,
TypeAttrBeginning,
TypeAttrInheritanceBeginning,
OptionalBinding,

/// Completion after `~` in an inheritance clause.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/IDE/CompletionLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
void getAttributeDeclParamCompletions(CustomSyntaxAttributeKind AttrKind,
int ParamIndex, bool HasLabel);

void getTypeAttributeKeywordCompletions();
void getTypeAttributeKeywordCompletions(CompletionKind completionKind);

void collectPrecedenceGroups();

Expand Down
2 changes: 2 additions & 0 deletions include/swift/Parse/IDEInspectionCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ class CodeCompletionCallbacks {

virtual void completeTypeAttrBeginning() {};

virtual void completeTypeAttrInheritanceBeginning() {};

virtual void completeOptionalBinding(){};

virtual void completeWithoutConstraintType(){};
Expand Down
75 changes: 40 additions & 35 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1249,45 +1249,10 @@ class Parser {
return isLifetimeDependenceToken();
}

struct ParsedTypeAttributeList {
ParamDecl::Specifier Specifier = ParamDecl::Specifier::Default;
SourceLoc SpecifierLoc;
SourceLoc IsolatedLoc;
SourceLoc ConstLoc;
SourceLoc ResultDependsOnLoc;
SourceLoc SendingLoc;
SmallVector<TypeOrCustomAttr> Attributes;
SmallVector<LifetimeDependenceSpecifier> lifetimeDependenceSpecifiers;

/// Main entry point for parsing.
///
/// Inline we just have the fast path of failing to match. We call slowParse
/// that contains the outline of more complex implementation. This is HOT
/// code!
ParserStatus parse(Parser &P) {
auto &Tok = P.Tok;
if (Tok.is(tok::at_sign) || P.isParameterSpecifier())
return slowParse(P);
return makeParserSuccess();
}

TypeRepr *applyAttributesToType(Parser &P, TypeRepr *Type) const;

private:
/// An out of line implementation of the more complicated cases. This
/// ensures on the inlined fast path we handle the case of not matching.
ParserStatus slowParse(Parser &P);
};

bool parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc,
ConventionTypeAttr *&result,
bool justChecking);

ParserStatus parseTypeAttribute(TypeOrCustomAttr &result, SourceLoc AtLoc,
SourceLoc AtEndLoc,
PatternBindingInitializer *&initContext,
bool justChecking = false);

ParserStatus parseLifetimeDependenceSpecifiers(
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList);

Expand Down Expand Up @@ -1426,6 +1391,8 @@ class Parser {

/// Whether the type is for a closure attribute.
CustomAttribute,
/// A type in an inheritance clause.
InheritanceClause,
};

ParserResult<TypeRepr> parseTypeScalar(
Expand Down Expand Up @@ -1482,6 +1449,44 @@ class Parser {
/// Parse a dotted type, e.g. 'Foo<X>.Y.Z', 'P.Type', '[X].Y'.
ParserResult<TypeRepr> parseTypeDotted(ParserResult<TypeRepr> Base);

struct ParsedTypeAttributeList {
ParseTypeReason ParseReason;
ParamDecl::Specifier Specifier = ParamDecl::Specifier::Default;
SourceLoc SpecifierLoc;
SourceLoc IsolatedLoc;
SourceLoc ConstLoc;
SourceLoc ResultDependsOnLoc;
SourceLoc SendingLoc;
SmallVector<TypeOrCustomAttr> Attributes;
SmallVector<LifetimeDependenceSpecifier> lifetimeDependenceSpecifiers;

ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {}

/// Main entry point for parsing.
///
/// Inline we just have the fast path of failing to match. We call slowParse
/// that contains the outline of more complex implementation. This is HOT
/// code!
ParserStatus parse(Parser &P) {
auto &Tok = P.Tok;
if (Tok.is(tok::at_sign) || P.isParameterSpecifier())
return slowParse(P);
return makeParserSuccess();
}

TypeRepr *applyAttributesToType(Parser &P, TypeRepr *Type) const;

private:
/// An out of line implementation of the more complicated cases. This
/// ensures on the inlined fast path we handle the case of not matching.
ParserStatus slowParse(Parser &P);
};

ParserStatus parseTypeAttribute(TypeOrCustomAttr &result, SourceLoc AtLoc,
SourceLoc AtEndLoc, ParseTypeReason reason,
PatternBindingInitializer *&initContext,
bool justChecking = false);

ParserResult<TypeRepr> parseOldStyleProtocolComposition();
ParserResult<TypeRepr> parseAnyType();
ParserResult<TypeRepr> parseSILBoxType(GenericParamList *generics,
Expand Down
18 changes: 18 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@ const char *TypeAttribute::getAttrName(TypeAttrKind kind) {
llvm_unreachable("unknown type attribute kind");
}

bool TypeAttribute::isUserInaccessible(TypeAttrKind DK) {
// Currently we can base this off whether it is underscored or for SIL.
// TODO: We could introduce a similar options scheme to DECL_ATTR if we ever
// need a user-inaccessible non-underscored attribute.
switch (DK) {
// SIL attributes are always considered user-inaccessible.
#define SIL_TYPE_ATTR(SPELLING, C) \
case TypeAttrKind::C: \
return true;
// For non-SIL attributes, check whether the spelling is underscored.
#define TYPE_ATTR(SPELLING, C) \
case TypeAttrKind::C: \
return StringRef(#SPELLING).starts_with("_");
#include "swift/AST/TypeAttr.def"
}
llvm_unreachable("unhandled case in switch!");
}

TypeAttribute *TypeAttribute::createSimple(const ASTContext &context,
TypeAttrKind kind,
SourceLoc atLoc,
Expand Down
13 changes: 10 additions & 3 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
void completeStmtLabel(StmtKind ParentKind) override;
void completeForEachPatternBeginning(bool hasTry, bool hasAwait) override;
void completeTypeAttrBeginning() override;
void completeTypeAttrInheritanceBeginning() override;
void completeOptionalBinding() override;
void completeWithoutConstraintType() override;

Expand Down Expand Up @@ -654,6 +655,11 @@ void CodeCompletionCallbacksImpl::completeTypeAttrBeginning() {
Kind = CompletionKind::TypeAttrBeginning;
}

void CodeCompletionCallbacksImpl::completeTypeAttrInheritanceBeginning() {
CurDeclContext = P.CurDeclContext;
Kind = CompletionKind::TypeAttrInheritanceBeginning;
}

bool swift::ide::isDynamicLookup(Type T) {
return T->getRValueType()->isAnyObject();
}
Expand Down Expand Up @@ -982,6 +988,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
case CompletionKind::PrecedenceGroup:
case CompletionKind::StmtLabel:
case CompletionKind::TypeAttrBeginning:
case CompletionKind::TypeAttrInheritanceBeginning:
case CompletionKind::OptionalBinding:
case CompletionKind::WithoutConstraintType:
break;
Expand Down Expand Up @@ -1930,14 +1937,14 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
Lookup.getStmtLabelCompletions(Loc, ParentStmtKind == StmtKind::Continue);
break;
}
case CompletionKind::TypeAttrBeginning: {
Lookup.getTypeAttributeKeywordCompletions();
case CompletionKind::TypeAttrBeginning:
case CompletionKind::TypeAttrInheritanceBeginning: {
Lookup.getTypeAttributeKeywordCompletions(Kind);

// Type names at attribute position after '@'.
Lookup.getTypeCompletionsInDeclContext(
P.Context.SourceMgr.getIDEInspectionTargetLoc());
break;

}
case CompletionKind::OptionalBinding: {
SourceLoc Loc = P.Context.SourceMgr.getIDEInspectionTargetLoc();
Expand Down
37 changes: 29 additions & 8 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3131,18 +3131,39 @@ void CompletionLookup::getAttributeDeclParamCompletions(
}
}

void CompletionLookup::getTypeAttributeKeywordCompletions() {
auto addTypeAttr = [&](StringRef Name) {
void CompletionLookup::getTypeAttributeKeywordCompletions(
CompletionKind completionKind) {
auto addTypeAttr = [&](TypeAttrKind Kind, StringRef Name) {
if (completionKind != CompletionKind::TypeAttrInheritanceBeginning) {
switch (Kind) {
case TypeAttrKind::Retroactive:
case TypeAttrKind::Preconcurrency:
case TypeAttrKind::Unchecked:
// These attributes are only available in inheritance clasuses.
return;
default:
break;
}
}
CodeCompletionResultBuilder Builder = makeResultBuilder(
CodeCompletionResultKind::Keyword, SemanticContextKind::None);
Builder.addAttributeKeyword(Name, "Type Attribute");
};
addTypeAttr("autoclosure");
addTypeAttr("convention(swift)");
addTypeAttr("convention(block)");
addTypeAttr("convention(c)");
addTypeAttr("convention(thin)");
addTypeAttr("escaping");

// Add simple user-accessible attributes.
#define SIL_TYPE_ATTR(SPELLING, C)
#define SIMPLE_SIL_TYPE_ATTR(SPELLING, C)
#define SIMPLE_TYPE_ATTR(SPELLING, C) \
if (!TypeAttribute::isUserInaccessible(TypeAttrKind::C)) \
addTypeAttr(TypeAttrKind::C, #SPELLING);
#include "swift/AST/TypeAttr.def"

// Add non-simple cases.
addTypeAttr(TypeAttrKind::Convention, "convention(swift)");
addTypeAttr(TypeAttrKind::Convention, "convention(block)");
addTypeAttr(TypeAttrKind::Convention, "convention(c)");
addTypeAttr(TypeAttrKind::Convention, "convention(thin)");
addTypeAttr(TypeAttrKind::Isolated, "isolated(any)");
}

void CompletionLookup::collectPrecedenceGroups() {
Expand Down
19 changes: 15 additions & 4 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4489,7 +4489,8 @@ bool Parser::canParseTypeAttribute() {
TypeOrCustomAttr result; // ignored
PatternBindingInitializer *initContext = nullptr;
return !parseTypeAttribute(result, /*atLoc=*/SourceLoc(),
/*atEndLoc=*/SourceLoc(), initContext,
/*atEndLoc=*/SourceLoc(),
ParseTypeReason::Unspecified, initContext,
/*justChecking*/ true)
.isError();
}
Expand Down Expand Up @@ -4690,6 +4691,7 @@ bool Parser::parseUUIDString(UUID &uuid, Diag<> diagnostic, bool justChecking) {
/// no need to actually record the attribute
ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
SourceLoc AtLoc, SourceLoc AtEndLoc,
ParseTypeReason reason,
PatternBindingInitializer *&initContext,
bool justChecking) {
if (AtEndLoc != Tok.getLoc()) {
Expand All @@ -4705,7 +4707,14 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
if (Tok.is(tok::code_complete)) {
if (!justChecking) {
if (CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeTypeAttrBeginning();
switch (reason) {
case ParseTypeReason::InheritanceClause:
CodeCompletionCallbacks->completeTypeAttrInheritanceBeginning();
break;
default:
CodeCompletionCallbacks->completeTypeAttrBeginning();
break;
}
}
}
consumeToken(tok::code_complete);
Expand Down Expand Up @@ -5534,7 +5543,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
TypeOrCustomAttr result;
SourceLoc AtEndLoc = Tok.getRange().getEnd();
SourceLoc AtLoc = P.consumeToken();
status |= P.parseTypeAttribute(result, AtLoc, AtEndLoc, initContext);
status |=
P.parseTypeAttribute(result, AtLoc, AtEndLoc, ParseReason, initContext);
if (status.isError())
return status;
if (result)
Expand Down Expand Up @@ -6803,7 +6813,8 @@ ParserStatus Parser::parseInheritance(
continue;
}

auto ParsedTypeResult = parseType();
auto ParsedTypeResult =
parseType(diag::expected_type, ParseTypeReason::InheritanceClause);
Status |= ParsedTypeResult;

// Record the type if its a single type.
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ SourceLoc Parser::tryCompleteFunctionParamTypeBeginning() {
// Skip over any starting parameter specifiers.
{
CancellableBacktrackingScope backtrack(*this);
ParsedTypeAttributeList attrs;
ParsedTypeAttributeList attrs(ParseTypeReason::Unspecified);
attrs.parse(*this);
if (!Tok.is(tok::code_complete))
return SourceLoc();
Expand Down
8 changes: 7 additions & 1 deletion lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,15 @@ ParserResult<TypeRepr> Parser::parseTypeScalar(
ParserStatus status;

// Parse attributes.
ParsedTypeAttributeList parsedAttributeList;
ParsedTypeAttributeList parsedAttributeList(reason);
status |= parsedAttributeList.parse(*this);

// If we have a completion, create an ErrorType.
if (status.hasCodeCompletion()) {
auto *ET = ErrorTypeRepr::create(Context, PreviousLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
}

// Parse generic parameters in SIL mode.
GenericParamList *generics = nullptr;
SourceLoc substitutedLoc;
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,8 @@ bool SILParser::parseSILType(SILType &Result,
}

// Parse attributes.
Parser::ParsedTypeAttributeList parsedAttrs;
Parser::ParsedTypeAttributeList parsedAttrs(
Parser::ParseTypeReason::Unspecified);
parsedAttrs.parse(P);

// Global functions are implicitly @convention(thin) if not specified otherwise.
Expand Down
Loading