mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
19
test/attr/typeEraser.swift
Normal file
19
test/attr/typeEraser.swift
Normal 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() {}
|
||||
|
||||
Reference in New Issue
Block a user