Skip to content

[Parse] Add an attribute for typeEraser. #29775

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 1 commit into from
Feb 12, 2020
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
5 changes: 5 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,11 @@ SIMPLE_DECL_ATTR(_inheritsConvenienceInitializers,
APIStableToAdd | ABIStableToAdd | APIBreakingToRemove | ABIBreakingToRemove,
93)

DECL_ATTR(_typeEraser, TypeEraser,
OnProtocol | UserInaccessible | NotSerialized |
ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove,
94)

SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction,
OnFunc |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
Expand Down
15 changes: 15 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,21 @@ class DynamicReplacementAttr final
}
};

/// The \c @_typeEraser(TypeEraserType) attribute.
class TypeEraserAttr final : public DeclAttribute {
TypeLoc TypeEraserLoc;
public:
TypeEraserAttr(SourceLoc atLoc, SourceRange range, TypeLoc typeEraserLoc)
: DeclAttribute(DAK_TypeEraser, atLoc, range, /*Implicit=*/false),
TypeEraserLoc(typeEraserLoc) {}

const TypeLoc &getTypeEraserLoc() const { return TypeEraserLoc; }

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_TypeEraser;
}
};

/// Represents any sort of access control modifier.
class AbstractAccessControlAttr : public DeclAttribute {
protected:
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,11 @@ ERROR(attr_dynamic_replacement_expected_for,none,
ERROR(attr_dynamic_replacement_expected_colon,none,
"expected ':' after @_dynamicReplacement(for", ())

ERROR(attr_type_eraser_expected_type_name,none,
"expected a type name in @_typeEraser()", ())
ERROR(attr_type_eraser_expected_rparen,none,
"expected ')' after type name for @_typeEraser", ())

ERROR(attr_private_import_expected_rparen,none,
"expected ')' after function name for @_private", ())
ERROR(attr_private_import_expected_sourcefile, none,
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,8 @@ StringRef DeclAttribute::getAttrName() const {
return "objc";
case DAK_DynamicReplacement:
return "_dynamicReplacement";
case DAK_TypeEraser:
return "_typeEraser";
case DAK_PrivateImport:
return "_private";
case DAK_RestatedObjCConformance:
Expand Down
31 changes: 31 additions & 0 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,37 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
break;
}

case DAK_TypeEraser: {
// Parse leading '('
if (Tok.isNot(tok::l_paren)) {
diagnose(Loc, diag::attr_expected_lparen, AttrName,
DeclAttribute::isDeclModifier(DK));
return false;
}

SourceLoc LParenLoc = consumeToken(tok::l_paren);
ParserResult<TypeRepr> ErasedType;
bool invalid = false;
{
// Parse type-eraser type
SyntaxParsingContext ContentContext(SyntaxContext, SyntaxKind::Type);
ErasedType = parseType(diag::attr_type_eraser_expected_type_name);
invalid = ErasedType.hasCodeCompletion() || ErasedType.isNull();
}

// Parse matching ')'
SourceLoc RParenLoc;
invalid |= parseMatchingToken(tok::r_paren, RParenLoc,
diag::attr_type_eraser_expected_rparen,
LParenLoc);
if (invalid)
return false;

Attributes.add(new (Context)
TypeEraserAttr(AtLoc, {Loc, RParenLoc}, ErasedType.get()));
break;
}

case DAK_Specialize: {
if (Tok.isNot(tok::l_paren)) {
diagnose(Loc, diag::attr_expected_lparen, AttrName,
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
IGNORED_ATTR(StaticInitializeObjCMetadata)
IGNORED_ATTR(SynthesizedProtocol)
IGNORED_ATTR(Testable)
IGNORED_ATTR(TypeEraser)
IGNORED_ATTR(WeakLinked)
IGNORED_ATTR(PrivateImport)
IGNORED_ATTR(DisfavoredOverload)
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckDeclOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,7 @@ namespace {
UNINTERESTING_ATTR(Convenience)
UNINTERESTING_ATTR(Semantics)
UNINTERESTING_ATTR(SetterAccess)
UNINTERESTING_ATTR(TypeEraser)
UNINTERESTING_ATTR(HasStorage)
UNINTERESTING_ATTR(UIApplicationMain)
UNINTERESTING_ATTR(UsableFromInline)
Expand Down
6 changes: 6 additions & 0 deletions lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,12 @@ namespace decls_block {
BCArray<IdentifierIDField>
>;

using TypeEraserDeclAttrLayout = BCRecordLayout<
TypeEraser_DECL_ATTR,
BCFixed<1>, // implicit flag
TypeIDField // type eraser type
>;

using CustomDeclAttrLayout = BCRecordLayout<
Custom_DECL_ATTR,
BCFixed<1>, // implicit flag
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2108,6 +2108,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
case DAK_RestatedObjCConformance:
case DAK_ClangImporterSynthesizedType:
case DAK_PrivateImport:
case DAK_TypeEraser:
llvm_unreachable("cannot serialize attribute");

case DAK_Count:
Expand Down
19 changes: 19 additions & 0 deletions test/attr/typeEraser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %target-swift-frontend -typecheck %s -verify

class AnyP: P1 {}

@_typeEraser(AnyP) // okay
protocol P1 {}

@_typeEraser // expected-error {{expected '(' in '_typeEraser' attribute}}
protocol P2 {}

@_typeEraser() // expected-error {{expected a type name in @_typeEraser()}}
protocol P3 {}

@_typeEraser(AnyP // expected-note {{to match this opening '('}}
protocol P4 {} // expected-error {{expected ')' after type name for @_typeEraser}}

@_typeEraser(AnyP) // expected-error {{@_typeEraser may only be used on 'protocol' declarations}}
func notAProtocol() {}