[Parse] Add an attribute for typeEraser.

This will be used for compiler-driven type erasure for dynamic
replacement of functions with an opaque return type. For now, just
parse the attribute and ignore it.
This commit is contained in:
Holly Borla
2020-02-11 16:18:24 -08:00
parent ff9d3ef073
commit ffba71b889
10 changed files with 86 additions and 0 deletions

View File

@@ -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,

View File

@@ -1108,6 +1108,21 @@ public:
}
};
/// 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:

View File

@@ -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,

View File

@@ -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:

View File

@@ -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,

View File

@@ -108,6 +108,7 @@ public:
IGNORED_ATTR(StaticInitializeObjCMetadata)
IGNORED_ATTR(SynthesizedProtocol)
IGNORED_ATTR(Testable)
IGNORED_ATTR(TypeEraser)
IGNORED_ATTR(WeakLinked)
IGNORED_ATTR(PrivateImport)
IGNORED_ATTR(DisfavoredOverload)

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

View File

@@ -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() {}