Skip to content

Commit

Permalink
Merge pull request swiftlang#74989 from hamishknight/attr-etc-6.0
Browse files Browse the repository at this point in the history
[6.0] [Completion] Update type attribute completions
  • Loading branch information
hamishknight authored Jul 6, 2024
2 parents 32b33fb + f8542d9 commit e14d3a3
Show file tree
Hide file tree
Showing 15 changed files with 164 additions and 71 deletions.
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)
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

0 comments on commit e14d3a3

Please sign in to comment.