Skip to content

Commit 8448e61

Browse files
committed
Add support for attributes on closures.
1 parent 2f584b5 commit 8448e61

File tree

11 files changed

+99
-10
lines changed

11 files changed

+99
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ ERROR(incorrect_explicit_closure_result,none,
283283
"declared closure result %0 is incompatible with contextual type %1",
284284
(Type, Type))
285285

286+
ERROR(unsupported_closure_attr,none,
287+
"%select{attribute |}0 '%1' is not supported on a closure",
288+
(bool, StringRef))
289+
286290
NOTE(suggest_expected_match,none,
287291
"%select{expected an argument list|produces result}0 of type '%1'",
288292
(bool, StringRef))

include/swift/AST/Expr.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef SWIFT_AST_EXPR_H
1818
#define SWIFT_AST_EXPR_H
1919

20+
#include "swift/AST/Attr.h"
2021
#include "swift/AST/CaptureInfo.h"
2122
#include "swift/AST/ConcreteDeclRef.h"
2223
#include "swift/AST/DeclContext.h"
@@ -3786,6 +3787,9 @@ class ClosureExpr : public AbstractClosureExpr {
37863787
};
37873788

37883789
private:
3790+
/// The attributes attached to the closure.
3791+
DeclAttributes Attributes;
3792+
37893793
/// The range of the brackets of the capture list, if present.
37903794
SourceRange BracketRange;
37913795

@@ -3818,13 +3822,14 @@ class ClosureExpr : public AbstractClosureExpr {
38183822
/// was originally just a single expression.
38193823
llvm::PointerIntPair<BraceStmt *, 1, bool> Body;
38203824
public:
3821-
ClosureExpr(SourceRange bracketRange, VarDecl *capturedSelfDecl,
3825+
ClosureExpr(const DeclAttributes &attributes,
3826+
SourceRange bracketRange, VarDecl *capturedSelfDecl,
38223827
ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc,
38233828
SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType,
38243829
unsigned discriminator, DeclContext *parent)
38253830
: AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
38263831
discriminator, parent),
3827-
BracketRange(bracketRange),
3832+
Attributes(attributes), BracketRange(bracketRange),
38283833
CapturedSelfDecl(capturedSelfDecl),
38293834
AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc),
38303835
InLoc(inLoc),
@@ -3845,6 +3850,9 @@ class ClosureExpr : public AbstractClosureExpr {
38453850
Body.setInt(isSingleExpression);
38463851
}
38473852

3853+
DeclAttributes &getAttrs() { return Attributes; }
3854+
const DeclAttributes &getAttrs() const { return Attributes; }
3855+
38483856
/// Determine whether the parameters of this closure are actually
38493857
/// anonymous closure variables.
38503858
bool hasAnonymousClosureVars() const {

include/swift/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ class Parser {
688688
/// Skip over SIL decls until we encounter the start of a Swift decl or eof.
689689
void skipSILUntilSwiftDecl();
690690

691+
/// Skip over any attribute.
692+
void skipAnyAttribute();
693+
691694
/// If the parser is generating only a syntax tree, try loading the current
692695
/// node from a previously generated syntax tree.
693696
/// Returns \c true if the node has been loaded and inserted into the current
@@ -1575,6 +1578,7 @@ class Parser {
15751578
/// \returns ParserStatus error if an error occurred. Success if no signature
15761579
/// is present or succssfully parsed.
15771580
ParserStatus parseClosureSignatureIfPresent(
1581+
DeclAttributes &attributes,
15781582
SourceRange &bracketRange,
15791583
SmallVectorImpl<CaptureListEntry> &captureList,
15801584
VarDecl *&capturedSelfParamDecl,

lib/Parse/ParseDecl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5728,6 +5728,15 @@ void Parser::skipSILUntilSwiftDecl() {
57285728
}
57295729
}
57305730

5731+
void Parser::skipAnyAttribute() {
5732+
consumeToken(tok::at_sign);
5733+
if (!consumeIf(tok::identifier))
5734+
return;
5735+
5736+
if (consumeIf(tok::l_paren))
5737+
skipUntil(tok::r_paren);
5738+
}
5739+
57315740
/// Returns a descriptive name for the given accessor/addressor kind.
57325741
static StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind,
57335742
bool article) {

lib/Parse/ParseExpr.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/Parse/Parser.h"
1818
#include "swift/AST/ASTWalker.h"
19+
#include "swift/AST/Attr.h"
1920
#include "swift/AST/DiagnosticsParse.h"
2021
#include "swift/AST/TypeRepr.h"
2122
#include "swift/Basic/EditorPlaceholder.h"
@@ -2335,6 +2336,7 @@ static void printTupleNames(const TypeRepr *typeRepr, llvm::raw_ostream &OS) {
23352336
}
23362337

23372338
ParserStatus Parser::parseClosureSignatureIfPresent(
2339+
DeclAttributes &attributes,
23382340
SourceRange &bracketRange,
23392341
SmallVectorImpl<CaptureListEntry> &captureList,
23402342
VarDecl *&capturedSelfDecl,
@@ -2344,6 +2346,7 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
23442346
TypeExpr *&explicitResultType, SourceLoc &inLoc) {
23452347
// Clear out result parameters.
23462348
bracketRange = SourceRange();
2349+
attributes = DeclAttributes();
23472350
capturedSelfDecl = nullptr;
23482351
params = nullptr;
23492352
throwsLoc = SourceLoc();
@@ -2360,9 +2363,16 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
23602363

23612364
// If we have a leading token that may be part of the closure signature, do a
23622365
// speculative parse to validate it and look for 'in'.
2363-
if (Tok.isAny(tok::l_paren, tok::l_square, tok::identifier, tok::kw__)) {
2366+
if (Tok.isAny(
2367+
tok::at_sign, tok::l_paren, tok::l_square, tok::identifier,
2368+
tok::kw__)) {
23642369
BacktrackingScope backtrack(*this);
23652370

2371+
// Consume attributes.
2372+
while (Tok.is(tok::at_sign)) {
2373+
skipAnyAttribute();
2374+
}
2375+
23662376
// Skip by a closure capture list if present.
23672377
if (consumeIf(tok::l_square)) {
23682378
skipUntil(tok::r_square);
@@ -2425,6 +2435,9 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
24252435
}
24262436
ParserStatus status;
24272437
SyntaxParsingContext ClosureSigCtx(SyntaxContext, SyntaxKind::ClosureSignature);
2438+
2439+
(void)parseDeclAttributeList(attributes);
2440+
24282441
if (Tok.is(tok::l_square) && peekToken().is(tok::r_square)) {
24292442

24302443
SyntaxParsingContext CaptureCtx(SyntaxContext,
@@ -2721,6 +2734,7 @@ ParserResult<Expr> Parser::parseExprClosure() {
27212734
SourceLoc leftBrace = consumeToken();
27222735

27232736
// Parse the closure-signature, if present.
2737+
DeclAttributes attributes;
27242738
SourceRange bracketRange;
27252739
SmallVector<CaptureListEntry, 2> captureList;
27262740
VarDecl *capturedSelfDecl;
@@ -2731,8 +2745,8 @@ ParserResult<Expr> Parser::parseExprClosure() {
27312745
TypeExpr *explicitResultType;
27322746
SourceLoc inLoc;
27332747
Status |= parseClosureSignatureIfPresent(
2734-
bracketRange, captureList, capturedSelfDecl, params, asyncLoc, throwsLoc,
2735-
arrowLoc, explicitResultType, inLoc);
2748+
attributes, bracketRange, captureList, capturedSelfDecl, params, asyncLoc,
2749+
throwsLoc, arrowLoc, explicitResultType, inLoc);
27362750

27372751
// If the closure was created in the context of an array type signature's
27382752
// size expression, there will not be a local context. A parse error will
@@ -2748,8 +2762,8 @@ ParserResult<Expr> Parser::parseExprClosure() {
27482762

27492763
// Create the closure expression and enter its context.
27502764
auto *closure = new (Context) ClosureExpr(
2751-
bracketRange, capturedSelfDecl, params, asyncLoc, throwsLoc, arrowLoc,
2752-
inLoc, explicitResultType, discriminator, CurDeclContext);
2765+
attributes, bracketRange, capturedSelfDecl, params, asyncLoc, throwsLoc,
2766+
arrowLoc, inLoc, explicitResultType, discriminator, CurDeclContext);
27532767
ParseFunctionBody cc(*this, closure);
27542768

27552769
// Handle parameters.

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7710,8 +7710,12 @@ namespace {
77107710
});
77117711

77127712
switch (result) {
7713-
case SolutionApplicationToFunctionResult::Success:
7713+
case SolutionApplicationToFunctionResult::Success: {
7714+
if (auto closure = dyn_cast_or_null<ClosureExpr>(
7715+
fn.getAbstractClosureExpr()))
7716+
TypeChecker::checkClosureAttributes(closure);
77147717
return false;
7718+
}
77157719

77167720
case SolutionApplicationToFunctionResult::Failure:
77177721
return true;

lib/Sema/DebuggerTestingTransform.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ class DebuggerTestingTransform : public ASTWalker {
226226
// Create the closure.
227227
auto *Params = ParameterList::createEmpty(Ctx);
228228
auto *Closure = new (Ctx)
229-
ClosureExpr(SourceRange(), nullptr, Params, SourceLoc(), SourceLoc(),
229+
ClosureExpr(DeclAttributes(), SourceRange(), nullptr, Params,
230+
SourceLoc(), SourceLoc(),
230231
SourceLoc(), SourceLoc(), nullptr,
231232
DF.getNextDiscriminator(), getCurrentDeclContext());
232233
Closure->setImplicit(true);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5475,4 +5475,32 @@ void AttributeChecker::visitReasyncAttr(ReasyncAttr *attr) {
54755475
// FIXME
54765476
}
54775477

5478-
void AttributeChecker::visitAtReasyncAttr(AtReasyncAttr *attr) {}
5478+
void AttributeChecker::visitAtReasyncAttr(AtReasyncAttr *attr) {}
5479+
5480+
namespace {
5481+
5482+
class ClosureAttributeChecker
5483+
: public AttributeVisitor<ClosureAttributeChecker> {
5484+
ASTContext &ctx;
5485+
ClosureExpr *closure;
5486+
public:
5487+
ClosureAttributeChecker(ClosureExpr *closure)
5488+
: ctx(closure->getASTContext()), closure(closure) { }
5489+
5490+
void visitDeclAttribute(DeclAttribute *attr) {
5491+
ctx.Diags.diagnose(
5492+
attr->getLocation(), diag::unsupported_closure_attr,
5493+
attr->isDeclModifier(), attr->getAttrName())
5494+
.fixItRemove(attr->getRangeWithAt());
5495+
attr->setInvalid();
5496+
}
5497+
};
5498+
5499+
}
5500+
5501+
void TypeChecker::checkClosureAttributes(ClosureExpr *closure) {
5502+
ClosureAttributeChecker checker(closure);
5503+
for (auto attr : closure->getAttrs()) {
5504+
checker.visit(attr);
5505+
}
5506+
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
20772077
}
20782078

20792079
bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
2080+
TypeChecker::checkClosureAttributes(closure);
20802081
TypeChecker::checkParameterList(closure->getParameters(), closure);
20812082

20822083
BraceStmt *body = closure->getBody();

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ void typeCheckDecl(Decl *D);
451451

452452
void addImplicitDynamicAttribute(Decl *D);
453453
void checkDeclAttributes(Decl *D);
454+
void checkClosureAttributes(ClosureExpr *closure);
454455
void checkParameterList(ParameterList *params, DeclContext *owner);
455456

456457
void diagnoseDuplicateBoundVars(Pattern *pattern);

test/attr/closures.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
2+
3+
func testNonacceptedClosures() {
4+
let fn = { @usableFromInline in // expected-error{{'usableFromInline' is not supported on a closure}}
5+
"hello"
6+
}
7+
8+
let fn2: (Int) -> Int = { @usableFromInline x in // expected-error{{'usableFromInline' is not supported on a closure}}
9+
print("hello")
10+
return x
11+
}
12+
13+
_ = fn
14+
_ = fn2
15+
}

0 commit comments

Comments
 (0)