Skip to content

Commit ffba71b

Browse files
committed
[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.
1 parent ff9d3ef commit ffba71b

File tree

10 files changed

+86
-0
lines changed

10 files changed

+86
-0
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,11 @@ SIMPLE_DECL_ATTR(_inheritsConvenienceInitializers,
519519
APIStableToAdd | ABIStableToAdd | APIBreakingToRemove | ABIBreakingToRemove,
520520
93)
521521

522+
DECL_ATTR(_typeEraser, TypeEraser,
523+
OnProtocol | UserInaccessible | NotSerialized |
524+
ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove,
525+
94)
526+
522527
SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction,
523528
OnFunc |
524529
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,

include/swift/AST/Attr.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,21 @@ class DynamicReplacementAttr final
11081108
}
11091109
};
11101110

1111+
/// The \c @_typeEraser(TypeEraserType) attribute.
1112+
class TypeEraserAttr final : public DeclAttribute {
1113+
TypeLoc TypeEraserLoc;
1114+
public:
1115+
TypeEraserAttr(SourceLoc atLoc, SourceRange range, TypeLoc typeEraserLoc)
1116+
: DeclAttribute(DAK_TypeEraser, atLoc, range, /*Implicit=*/false),
1117+
TypeEraserLoc(typeEraserLoc) {}
1118+
1119+
const TypeLoc &getTypeEraserLoc() const { return TypeEraserLoc; }
1120+
1121+
static bool classof(const DeclAttribute *DA) {
1122+
return DA->getKind() == DAK_TypeEraser;
1123+
}
1124+
};
1125+
11111126
/// Represents any sort of access control modifier.
11121127
class AbstractAccessControlAttr : public DeclAttribute {
11131128
protected:

include/swift/AST/DiagnosticsParse.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,11 @@ ERROR(attr_dynamic_replacement_expected_for,none,
14881488
ERROR(attr_dynamic_replacement_expected_colon,none,
14891489
"expected ':' after @_dynamicReplacement(for", ())
14901490

1491+
ERROR(attr_type_eraser_expected_type_name,none,
1492+
"expected a type name in @_typeEraser()", ())
1493+
ERROR(attr_type_eraser_expected_rparen,none,
1494+
"expected ')' after type name for @_typeEraser", ())
1495+
14911496
ERROR(attr_private_import_expected_rparen,none,
14921497
"expected ')' after function name for @_private", ())
14931498
ERROR(attr_private_import_expected_sourcefile, none,

lib/AST/Attr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,8 @@ StringRef DeclAttribute::getAttrName() const {
10941094
return "objc";
10951095
case DAK_DynamicReplacement:
10961096
return "_dynamicReplacement";
1097+
case DAK_TypeEraser:
1098+
return "_typeEraser";
10971099
case DAK_PrivateImport:
10981100
return "_private";
10991101
case DAK_RestatedObjCConformance:

lib/Parse/ParseDecl.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,37 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
21752175
break;
21762176
}
21772177

2178+
case DAK_TypeEraser: {
2179+
// Parse leading '('
2180+
if (Tok.isNot(tok::l_paren)) {
2181+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
2182+
DeclAttribute::isDeclModifier(DK));
2183+
return false;
2184+
}
2185+
2186+
SourceLoc LParenLoc = consumeToken(tok::l_paren);
2187+
ParserResult<TypeRepr> ErasedType;
2188+
bool invalid = false;
2189+
{
2190+
// Parse type-eraser type
2191+
SyntaxParsingContext ContentContext(SyntaxContext, SyntaxKind::Type);
2192+
ErasedType = parseType(diag::attr_type_eraser_expected_type_name);
2193+
invalid = ErasedType.hasCodeCompletion() || ErasedType.isNull();
2194+
}
2195+
2196+
// Parse matching ')'
2197+
SourceLoc RParenLoc;
2198+
invalid |= parseMatchingToken(tok::r_paren, RParenLoc,
2199+
diag::attr_type_eraser_expected_rparen,
2200+
LParenLoc);
2201+
if (invalid)
2202+
return false;
2203+
2204+
Attributes.add(new (Context)
2205+
TypeEraserAttr(AtLoc, {Loc, RParenLoc}, ErasedType.get()));
2206+
break;
2207+
}
2208+
21782209
case DAK_Specialize: {
21792210
if (Tok.isNot(tok::l_paren)) {
21802211
diagnose(Loc, diag::attr_expected_lparen, AttrName,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
108108
IGNORED_ATTR(StaticInitializeObjCMetadata)
109109
IGNORED_ATTR(SynthesizedProtocol)
110110
IGNORED_ATTR(Testable)
111+
IGNORED_ATTR(TypeEraser)
111112
IGNORED_ATTR(WeakLinked)
112113
IGNORED_ATTR(PrivateImport)
113114
IGNORED_ATTR(DisfavoredOverload)

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,7 @@ namespace {
14341434
UNINTERESTING_ATTR(Convenience)
14351435
UNINTERESTING_ATTR(Semantics)
14361436
UNINTERESTING_ATTR(SetterAccess)
1437+
UNINTERESTING_ATTR(TypeEraser)
14371438
UNINTERESTING_ATTR(HasStorage)
14381439
UNINTERESTING_ATTR(UIApplicationMain)
14391440
UNINTERESTING_ATTR(UsableFromInline)

lib/Serialization/ModuleFormat.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,12 @@ namespace decls_block {
18231823
BCArray<IdentifierIDField>
18241824
>;
18251825

1826+
using TypeEraserDeclAttrLayout = BCRecordLayout<
1827+
TypeEraser_DECL_ATTR,
1828+
BCFixed<1>, // implicit flag
1829+
TypeIDField // type eraser type
1830+
>;
1831+
18261832
using CustomDeclAttrLayout = BCRecordLayout<
18271833
Custom_DECL_ATTR,
18281834
BCFixed<1>, // implicit flag

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,6 +2108,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
21082108
case DAK_RestatedObjCConformance:
21092109
case DAK_ClangImporterSynthesizedType:
21102110
case DAK_PrivateImport:
2111+
case DAK_TypeEraser:
21112112
llvm_unreachable("cannot serialize attribute");
21122113

21132114
case DAK_Count:

test/attr/typeEraser.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend -typecheck %s -verify
2+
3+
class AnyP: P1 {}
4+
5+
@_typeEraser(AnyP) // okay
6+
protocol P1 {}
7+
8+
@_typeEraser // expected-error {{expected '(' in '_typeEraser' attribute}}
9+
protocol P2 {}
10+
11+
@_typeEraser() // expected-error {{expected a type name in @_typeEraser()}}
12+
protocol P3 {}
13+
14+
@_typeEraser(AnyP // expected-note {{to match this opening '('}}
15+
protocol P4 {} // expected-error {{expected ')' after type name for @_typeEraser}}
16+
17+
@_typeEraser(AnyP) // expected-error {{@_typeEraser may only be used on 'protocol' declarations}}
18+
func notAProtocol() {}
19+

0 commit comments

Comments
 (0)