Skip to content

Commit a77539a

Browse files
authored
Merge pull request #3425 from tanadeau/sr-1952-add-escaping-parsing
[WIP][Parser][SR-1952] Added @escaping attribute parsing
2 parents 16143ca + 6ef59c0 commit a77539a

19 files changed

+84
-14
lines changed

include/swift/AST/Attr.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ TYPE_ATTR(autoclosure)
3535
TYPE_ATTR(convention)
3636
TYPE_ATTR(noreturn)
3737
TYPE_ATTR(noescape)
38+
TYPE_ATTR(escaping)
3839

3940
// SIL-specific attributes
4041
TYPE_ATTR(block_storage)
@@ -263,6 +264,8 @@ SIMPLE_DECL_ATTR(discardableResult, DiscardableResult,
263264

264265
SIMPLE_DECL_ATTR(GKInspectable, GKInspectable, OnVar, 66)
265266

267+
SIMPLE_DECL_ATTR(escaping, Escaping, OnParam, 67)
268+
266269
#undef TYPE_ATTR
267270
#undef DECL_ATTR_ALIAS
268271
#undef SIMPLE_DECL_ATTR

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,6 @@ ERROR(attr_swift3_migration_expected_rparen,none,
12431243
ERROR(attr_bad_swift_name,none,
12441244
"ill-formed Swift name '%0'", (StringRef))
12451245

1246-
12471246
// unowned
12481247
ERROR(attr_unowned_invalid_specifier,none,
12491248
"expected 'safe' or 'unsafe'", ())
@@ -1256,6 +1255,10 @@ WARNING(attr_warn_unused_result_removed,none,
12561255
ERROR(attr_warn_unused_result_expected_rparen,none,
12571256
"expected ')' after 'warn_unused_result' attribute", ())
12581257

1258+
// escaping
1259+
ERROR(attr_escaping_conflicts_noescape,none,
1260+
"@escaping conflicts with @noescape", ())
1261+
12591262
//------------------------------------------------------------------------------
12601263
// Generics parsing diagnostics
12611264
//------------------------------------------------------------------------------

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,7 +1788,8 @@ ERROR(noescape_implied_by_autoclosure,none,
17881788
"redundantly specified", ())
17891789
ERROR(noescape_conflicts_escaping_autoclosure,none,
17901790
"@noescape conflicts with @autoclosure(escaping)", ())
1791-
1791+
ERROR(escaping_function_type,none,
1792+
"@escaping may only be applied to parameters of function type", ())
17921793

17931794
// NSManaged attribute
17941795
ERROR(attr_NSManaged_not_instance_member,none,

include/swift/AST/Types.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,11 +2126,12 @@ class AnyFunctionType : public TypeBase {
21262126
// |representation|isAutoClosure|noReturn|noEscape|throws|
21272127
// | 0 .. 3 | 4 | 5 | 6 | 7 |
21282128
//
2129-
enum : uint16_t { RepresentationMask = 0x00F };
2130-
enum : uint16_t { AutoClosureMask = 0x010 };
2131-
enum : uint16_t { NoReturnMask = 0x020 };
2132-
enum : uint16_t { NoEscapeMask = 0x040 };
2133-
enum : uint16_t { ThrowsMask = 0x080 };
2129+
enum : uint16_t { RepresentationMask = 0x00F };
2130+
enum : uint16_t { AutoClosureMask = 0x010 };
2131+
enum : uint16_t { NoReturnMask = 0x020 };
2132+
enum : uint16_t { NoEscapeMask = 0x040 };
2133+
enum : uint16_t { ThrowsMask = 0x080 };
2134+
enum : uint16_t { ExplicitlyEscapingMask = 0x100 };
21342135

21352136
uint16_t Bits;
21362137

@@ -2153,15 +2154,18 @@ class AnyFunctionType : public TypeBase {
21532154

21542155
// Constructor with no defaults.
21552156
ExtInfo(Representation Rep, bool IsNoReturn,
2156-
bool IsAutoClosure, bool IsNoEscape, bool Throws)
2157+
bool IsAutoClosure, bool IsNoEscape, bool IsExplicitlyEscaping,
2158+
bool Throws)
21572159
: ExtInfo(Rep, IsNoReturn, Throws) {
21582160
Bits |= (IsAutoClosure ? AutoClosureMask : 0);
21592161
Bits |= (IsNoEscape ? NoEscapeMask : 0);
2162+
Bits |= (IsExplicitlyEscaping ? ExplicitlyEscapingMask : 0);
21602163
}
21612164

21622165
bool isNoReturn() const { return Bits & NoReturnMask; }
21632166
bool isAutoClosure() const { return Bits & AutoClosureMask; }
21642167
bool isNoEscape() const { return Bits & NoEscapeMask; }
2168+
bool isExplicitlyEscaping() const { return Bits & ExplicitlyEscapingMask; }
21652169
bool throws() const { return Bits & ThrowsMask; }
21662170
Representation getRepresentation() const {
21672171
unsigned rawRep = Bits & RepresentationMask;
@@ -2294,6 +2298,12 @@ class AnyFunctionType : public TypeBase {
22942298
bool isNoEscape() const {
22952299
return getExtInfo().isNoEscape();
22962300
}
2301+
2302+
/// \brief True if the parameter declaration it is attached to has explicitly
2303+
/// been marked with the @escaping attribute. This is a temporary measure.
2304+
bool isExplicitlyEscaping() const {
2305+
return getExtInfo().isExplicitlyEscaping();
2306+
}
22972307

22982308
bool throws() const {
22992309
return getExtInfo().throws();

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ namespace decls_block {
589589
BCFixed<1>, // auto-closure?
590590
BCFixed<1>, // noreturn?
591591
BCFixed<1>, // noescape?
592+
BCFixed<1>, // explicitlyEscaping?
592593
BCFixed<1> // throws?
593594
>;
594595

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,7 @@ namespace {
28552855
printFlag(T->isNoReturn(), "noreturn");
28562856
printFlag(T->isAutoClosure(), "autoclosure");
28572857
printFlag(T->isNoEscape(), "noescape");
2858+
printFlag(T->isExplicitlyEscaping(), "escaping");
28582859
printFlag(T->throws(), "throws");
28592860

28602861
printRec("input", T->getInput());

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3661,9 +3661,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
36613661
Printer << "@autoclosure ";
36623662
else
36633663
Printer << "@autoclosure(escaping) ";
3664-
} else if (info.isNoEscape())
3664+
} else if (info.isNoEscape()) {
36653665
// autoclosure implies noescape.
36663666
Printer << "@noescape ";
3667+
} else if (info.isExplicitlyEscaping()) {
3668+
Printer << "@escaping ";
3669+
}
36673670

36683671
if (Options.PrintFunctionRepresentationAttrs) {
36693672
// TODO: coalesce into a single convention attribute.

lib/AST/TypeRepr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ void AttributedTypeRepr::printAttrs(ASTPrinter &Printer) const {
283283
case 2: Printer << "@autoclosure(escaping) "; break;
284284
case 3: Printer << "@autoclosure "; break;
285285
}
286+
if (Attrs.has(TAK_escaping)) Printer << "@escaping ";
286287
if (Attrs.has(TAK_thin)) Printer << "@thin ";
287288
if (Attrs.has(TAK_thick)) Printer << "@thick ";
288289
if (Attrs.convention.hasValue()) {

lib/Parse/ParseDecl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,18 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
15221522
diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
15231523
return false;
15241524
}
1525+
// You can't specify @noescape and @escaping together.
1526+
if (Attributes.has(TAK_escaping)) {
1527+
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
1528+
return false;
1529+
}
1530+
break;
1531+
case TAK_escaping:
1532+
// You can't specify @noescape and @escaping together.
1533+
if (Attributes.has(TAK_noescape)) {
1534+
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
1535+
return false;
1536+
}
15251537
break;
15261538
case TAK_out:
15271539
case TAK_in:

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5479,6 +5479,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
54795479
toEI.isNoReturn() | fromEI.isNoReturn(),
54805480
toEI.isAutoClosure(),
54815481
toEI.isNoEscape() | fromEI.isNoEscape(),
5482+
toEI.isExplicitlyEscaping() | fromEI.isExplicitlyEscaping(),
54825483
toEI.throws() & fromEI.throws());
54835484
auto newToType = FunctionType::get(fromFunc->getInput(),
54845485
fromFunc->getResult(), newEI);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
9898
TC.checkNoEscapeAttr(cast<ParamDecl>(D), attr);
9999
}
100100

101+
void visitEscapingAttr(EscapingAttr *attr) {
102+
auto *PD = cast<ParamDecl>(D);
103+
auto *FTy = PD->getType()->getAs<FunctionType>();
104+
if (FTy == 0) {
105+
TC.diagnose(attr->getLocation(), diag::escaping_function_type);
106+
attr->setInvalid();
107+
}
108+
}
109+
101110
void visitTransparentAttr(TransparentAttr *attr);
102111
void visitMutationAttr(DeclAttribute *attr);
103112
void visitMutatingAttr(MutatingAttr *attr) { visitMutationAttr(attr); }
@@ -668,6 +677,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
668677
IGNORED_ATTR(WarnUnqualifiedAccess)
669678
IGNORED_ATTR(ShowInInterface)
670679
IGNORED_ATTR(DiscardableResult)
680+
IGNORED_ATTR(Escaping)
671681

672682
// FIXME: We actually do have things to enforce for versioned API.
673683
IGNORED_ATTR(Versioned)

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5228,6 +5228,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
52285228
// These can't appear on overridable declarations.
52295229
UNINTERESTING_ATTR(AutoClosure)
52305230
UNINTERESTING_ATTR(NoEscape)
5231+
UNINTERESTING_ATTR(Escaping)
52315232

52325233
UNINTERESTING_ATTR(Prefix)
52335234
UNINTERESTING_ATTR(Postfix)

lib/Sema/TypeCheckType.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
17391739
// function-type creator.
17401740
static const TypeAttrKind FunctionAttrs[] = {
17411741
TAK_convention, TAK_noreturn, TAK_pseudogeneric,
1742-
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure
1742+
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure,
1743+
TAK_escaping
17431744
};
17441745

17451746
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
@@ -1858,6 +1859,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
18581859
attrs.has(TAK_noreturn),
18591860
attrs.has(TAK_autoclosure),
18601861
attrs.has(TAK_noescape),
1862+
attrs.has(TAK_escaping),
18611863
fnRepr->throws());
18621864

18631865
ty = resolveASTFunctionType(fnRepr, options, extInfo);

lib/Serialization/Deserialization.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3434,13 +3434,14 @@ Type ModuleFile::getType(TypeID TID) {
34343434
TypeID inputID;
34353435
TypeID resultID;
34363436
uint8_t rawRepresentation;
3437-
bool autoClosure, noreturn, noescape, throws;
3437+
bool autoClosure, noreturn, noescape, explicitlyEscaping, throws;
34383438

34393439
decls_block::FunctionTypeLayout::readRecord(scratch, inputID, resultID,
34403440
rawRepresentation,
34413441
autoClosure,
34423442
noreturn,
34433443
noescape,
3444+
explicitlyEscaping,
34443445
throws);
34453446
auto representation = getActualFunctionTypeRepresentation(rawRepresentation);
34463447
if (!representation.hasValue()) {
@@ -3449,7 +3450,8 @@ Type ModuleFile::getType(TypeID TID) {
34493450
}
34503451

34513452
auto Info = FunctionType::ExtInfo(*representation,
3452-
noreturn, autoClosure, noescape, throws);
3453+
noreturn, autoClosure, noescape,
3454+
explicitlyEscaping, throws);
34533455

34543456
typeOrOffset = FunctionType::get(getType(inputID), getType(resultID),
34553457
Info);

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,7 @@ void Serializer::writeType(Type ty) {
29512951
fnTy->isAutoClosure(),
29522952
fnTy->isNoReturn(),
29532953
fnTy->isNoEscape(),
2954+
fnTy->isExplicitlyEscaping(),
29542955
fnTy->throws());
29552956
break;
29562957
}

test/IDE/complete_decl_attribute.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@
3535

3636
func method(@#^KEYWORD1^#) {}
3737

38-
// KEYWORD1: Begin completions, 2 items
38+
// KEYWORD1: Begin completions, 3 items
3939
// KEYWORD1-NEXT: Keyword/None: autoclosure[#Param Attribute#]; name=autoclosure{{$}}
4040
// KEYWORD1-NEXT: Keyword/None: noescape[#Param Attribute#]; name=noescape{{$}}
41+
// KEYWORD1-NEXT: Keyword/None: escaping[#Param Attribute#]; name=escaping{{$}}
4142
// KEYWORD1-NEXT: End completions
4243

4344
@#^KEYWORD2^#
@@ -89,7 +90,7 @@ struct S{}
8990

9091
@#^KEYWORD_LAST^#
9192

92-
// KEYWORD_LAST: Begin completions, 21 items
93+
// KEYWORD_LAST: Begin completions, 22 items
9394
// KEYWORD_LAST-NEXT: Keyword/None: available[#Declaration Attribute#]; name=available{{$}}
9495
// KEYWORD_LAST-NEXT: Keyword/None: objc[#Declaration Attribute#]; name=objc{{$}}
9596
// KEYWORD_LAST-NEXT: Keyword/None: swift3_migration[#Declaration Attribute#]; name=swift3_migration{{$}}
@@ -111,4 +112,5 @@ struct S{}
111112
// KEYWORD_LAST-NEXT: Keyword/None: warn_unqualified_access[#Declaration Attribute#]; name=warn_unqualified_access
112113
// KEYWORD_LAST-NEXT: Keyword/None: discardableResult[#Declaration Attribute#]; name=discardableResult
113114
// KEYWORD_LAST-NEXT: Keyword/None: GKInspectable[#Declaration Attribute#]; name=GKInspectable{{$}}
115+
// KEYWORD_LAST-NEXT: Keyword/None: escaping[#Declaration Attribute#]; name=escaping{{$}}
114116
// KEYWORD_LAST-NEXT: End completions

test/IDE/print_ast_tc_decls.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,11 @@ public func ParamAttrs3(a : @noescape () -> ()) {
13201320
a()
13211321
}
13221322

1323+
// PASS_PRINT_AST: public func ParamAttrs4(a: @escaping () -> ())
1324+
public func ParamAttrs4(a : @escaping () -> ()) {
1325+
a()
1326+
}
1327+
13231328
// Protocol extensions
13241329

13251330
protocol ProtocolToExtend {

test/attr/attr_escaping.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
@escaping var fn : () -> Int = { 4 } // expected-error {{@escaping may only be used on 'parameter' declarations}} {{1-11=}}
4+
5+
func wrongParamType(a: @escaping Int) {} // expected-error {{@escaping attribute only applies to function types}}
6+
7+
func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
8+
9+
func takesEscaping(_ fn: @escaping () -> Int) {} // ok

test/attr/attr_noescape.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
@noescape var fn : () -> Int = { 4 } // expected-error {{@noescape may only be used on 'parameter' declarations}} {{1-11=}}
44

5+
func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
6+
57
func doesEscape(_ fn : () -> Int) {}
68

79
func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {}

0 commit comments

Comments
 (0)