Skip to content

Commit c57b80a

Browse files
committed
Final walker cleanups
Instead of tracking the single-expression closures in a separate structure and passing that in under the right conditions, it makes more sense to simply set the 'Where' decl context to the single-expr closure and use the correct declaration context to determine whether the context is async. The reduces the number of variables that need to get plumbed through to the actual unavailable-from-async check and simplifies the actual check from figuring out whether we're in a single-expr closure or in an async context.
1 parent d99e331 commit c57b80a

File tree

5 files changed

+67
-47
lines changed

5 files changed

+67
-47
lines changed

include/swift/AST/Expr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3601,6 +3601,13 @@ class AbstractClosureExpr : public DeclContext, public Expr {
36013601
/// Only valid when \c hasSingleExpressionBody() is true.
36023602
Expr *getSingleExpressionBody() const;
36033603

3604+
/// Whether this closure has a body
3605+
bool hasBody() const;
3606+
3607+
/// Returns the body of closures that have a body
3608+
/// returns nullptr if the closure doesn't have a body
3609+
BraceStmt *getBody() const;
3610+
36043611
ClosureActorIsolation getActorIsolation() const { return actorIsolation; }
36053612

36063613
void setActorIsolation(ClosureActorIsolation actorIsolation) {

lib/AST/Expr.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,26 @@ void AbstractClosureExpr::setParameterList(ParameterList *P) {
16741674
P->setDeclContextOfParamDecls(this);
16751675
}
16761676

1677+
bool AbstractClosureExpr::hasBody() const {
1678+
switch (getKind()) {
1679+
case ExprKind::Closure:
1680+
case ExprKind::AutoClosure:
1681+
return true;
1682+
default:
1683+
return false;
1684+
}
1685+
}
1686+
1687+
BraceStmt * AbstractClosureExpr::getBody() const {
1688+
if (!hasBody())
1689+
return nullptr;
1690+
if (const AutoClosureExpr *autocls = dyn_cast<AutoClosureExpr>(this))
1691+
return autocls->getBody();
1692+
if (const ClosureExpr *cls = dyn_cast<ClosureExpr>(this))
1693+
return cls->getBody();
1694+
llvm_unreachable("Unknown closure expression");
1695+
}
1696+
16771697
Type AbstractClosureExpr::getResultType(
16781698
llvm::function_ref<Type(Expr *)> getType) const {
16791699
auto *E = const_cast<AbstractClosureExpr *>(this);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,8 +2083,7 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
20832083
}
20842084

20852085
auto where = ExportContext::forDeclSignature(D);
2086-
diagnoseDeclAvailability(mainFunction, attr->getRange(), nullptr, where, None,
2087-
/*containingClosure*/ nullptr);
2086+
diagnoseDeclAvailability(mainFunction, attr->getRange(), nullptr, where, None);
20882087

20892088
auto *const func = FuncDecl::createImplicit(
20902089
context, StaticSpellingKind::KeywordStatic,

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2767,7 +2767,6 @@ class ExprAvailabilityWalker : public ASTWalker {
27672767
ASTContext &Context;
27682768
MemberAccessContext AccessContext = MemberAccessContext::Getter;
27692769
SmallVector<const Expr *, 16> ExprStack;
2770-
SmallVector<ClosureExpr *, 4> singleExprClosureStack;
27712770
const ExportContext &Where;
27722771

27732772
public:
@@ -2848,16 +2847,20 @@ class ExprAvailabilityWalker : public ASTWalker {
28482847
E->getLoc(), Where);
28492848
}
28502849

2851-
// multi-statement closures are collected by ExprWalker::rewriteFunction
2852-
// and checked by ExprWalker::processDelayed in CSApply.cpp.
2853-
// Single-statement closures only have the attributes checked
2854-
// by TypeChecker::checkClosureAttributes in that rewriteFunction.
2855-
// As a result, we never see single-statement closures as the decl context
2856-
// in out 'where' here. By keeping a stack of closures, we can see if
2857-
// we're inside of one of these closures and go from there.
2858-
if (ClosureExpr *closure = dyn_cast<ClosureExpr>(E)) {
2859-
if (closure->hasSingleExpressionBody())
2860-
singleExprClosureStack.push_back(closure);
2850+
if (AbstractClosureExpr *closure = dyn_cast<AbstractClosureExpr>(E)) {
2851+
// Multi-statement closures are collected by ExprWalker::rewriteFunction
2852+
// and checked by ExprWalker::processDelayed in CSApply.cpp.
2853+
// Single-statement closures only have the attributes checked
2854+
// by TypeChecker::checkClosureAttributes in that rewriteFunction.
2855+
// Multi-statement closures will be checked explicitly later (as the decl
2856+
// context in the Where). Single-expression closures will not be
2857+
// revisited, and are not automatically set as the context of the 'where'.
2858+
// Don't double-check multi-statement closures, but do check
2859+
// single-statement closures, setting the closure as the decl context.
2860+
if (closure->hasSingleExpressionBody()) {
2861+
walkAbstractClosure(closure);
2862+
return skipChildren();
2863+
}
28612864
}
28622865

28632866
return visitChildren();
@@ -2867,14 +2870,6 @@ class ExprAvailabilityWalker : public ASTWalker {
28672870
assert(ExprStack.back() == E);
28682871
ExprStack.pop_back();
28692872

2870-
if (ClosureExpr *closure = dyn_cast<ClosureExpr>(E)) {
2871-
if (closure->hasSingleExpressionBody()) {
2872-
assert(closure == singleExprClosureStack.back() &&
2873-
"Popping wrong closure");
2874-
singleExprClosureStack.pop_back();
2875-
}
2876-
}
2877-
28782873
return E;
28792874
}
28802875

@@ -2885,10 +2880,7 @@ class ExprAvailabilityWalker : public ASTWalker {
28852880
// contain statements and declarations. We need to walk them recursively,
28862881
// since these availability for these statements is not diagnosed from
28872882
// typeCheckStmt() as usual.
2888-
DeclContext *dc = singleExprClosureStack.empty()
2889-
? Where.getDeclContext()
2890-
: singleExprClosureStack.back();
2891-
diagnoseStmtAvailability(S, dc, /*walkRecursively=*/true);
2883+
diagnoseStmtAvailability(S, Where.getDeclContext(), /*walkRecursively=*/true);
28922884
return std::make_pair(false, S);
28932885
}
28942886

@@ -3007,6 +2999,21 @@ class ExprAvailabilityWalker : public ASTWalker {
30072999
walkInContext(E, E->getSubExpr(), MemberAccessContext::InOut);
30083000
}
30093001

3002+
/// Walk an abstract closure expression, checking for availability
3003+
void walkAbstractClosure(AbstractClosureExpr *closure) {
3004+
// Do the walk with the closure set as the decl context of the 'where'
3005+
auto where = ExportContext::forFunctionBody(closure, closure->getStartLoc());
3006+
if (where.isImplicit())
3007+
return;
3008+
ExprAvailabilityWalker walker(where);
3009+
3010+
// Manually dive into the body
3011+
closure->getBody()->walk(walker);
3012+
3013+
return;
3014+
}
3015+
3016+
30103017
/// Walk the given expression in the member access context.
30113018
void walkInContext(Expr *baseExpr, Expr *E,
30123019
MemberAccessContext AccessContext) {
@@ -3068,7 +3075,7 @@ class ExprAvailabilityWalker : public ASTWalker {
30683075
Flags &= DeclAvailabilityFlag::ForInout;
30693076
Flags |= DeclAvailabilityFlag::ContinueOnPotentialUnavailability;
30703077
if (diagnoseDeclAvailability(D, ReferenceRange, /*call*/ nullptr, Where,
3071-
Flags, nullptr))
3078+
Flags))
30723079
return;
30733080
}
30743081
};
@@ -3091,9 +3098,7 @@ bool ExprAvailabilityWalker::diagnoseDeclRefAvailability(
30913098
return true;
30923099
}
30933100

3094-
const ClosureExpr *closure =
3095-
singleExprClosureStack.empty() ? nullptr : singleExprClosureStack.back();
3096-
diagnoseDeclAvailability(D, R, call, Where, Flags, closure);
3101+
diagnoseDeclAvailability(D, R, call, Where, Flags);
30973102

30983103
if (R.isValid()) {
30993104
if (diagnoseSubstitutionMapAvailability(R.Start, declRef.getSubstitutions(),
@@ -3110,8 +3115,7 @@ bool ExprAvailabilityWalker::diagnoseDeclRefAvailability(
31103115
/// Returns true if a diagnostic was emitted, false otherwise.
31113116
static bool
31123117
diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
3113-
const Expr *call, const ExportContext &Where,
3114-
const ClosureExpr *singleExprClosure) {
3118+
const Expr *call, const ExportContext &Where) {
31153119
// FIXME: I don't think this is right, but I don't understand the issue well
31163120
// enough to fix it properly. If the decl context is an abstract
31173121
// closure, we need it to have a type assigned to it before we can
@@ -3140,15 +3144,8 @@ diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
31403144
return false;
31413145
}
31423146

3143-
// If we're directly in a sync closure, then we are not in an async context.
3144-
// If we're directly in a sync closure, or we're not in a closure and the
3145-
// outer context is not async, we are in a sync context.
3146-
const bool inSingleClosure = singleExprClosure;
3147-
const bool inSyncClosure =
3148-
inSingleClosure && !singleExprClosure->isAsyncContext();
3149-
const bool inSyncContext =
3150-
!inSingleClosure && !Where.getDeclContext()->isAsyncContext();
3151-
if (inSyncClosure || inSyncContext)
3147+
// If we are in a synchronous context, don't check it
3148+
if (!Where.getDeclContext()->isAsyncContext())
31523149
return false;
31533150
if (!D->getAttrs().hasAttribute<UnavailableFromAsyncAttr>())
31543151
return false;
@@ -3168,8 +3165,7 @@ diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
31683165
bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
31693166
const Expr *call,
31703167
const ExportContext &Where,
3171-
DeclAvailabilityFlags Flags,
3172-
const ClosureExpr *singleExprClosure) {
3168+
DeclAvailabilityFlags Flags) {
31733169
assert(!Where.isImplicit());
31743170

31753171
// Generic parameters are always available.
@@ -3197,7 +3193,7 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
31973193
if (diagnoseExplicitUnavailability(D, R, Where, call, Flags))
31983194
return true;
31993195

3200-
if (diagnoseDeclUnavailableFromAsync(D, R, call, Where, singleExprClosure))
3196+
if (diagnoseDeclUnavailableFromAsync(D, R, call, Where))
32013197
return true;
32023198

32033199
// Make sure not to diagnose an accessor's deprecation if we already
@@ -3448,8 +3444,7 @@ class TypeReprAvailabilityWalker : public ASTWalker {
34483444
bool checkComponentIdentTypeRepr(ComponentIdentTypeRepr *ITR) {
34493445
if (auto *typeDecl = ITR->getBoundDecl()) {
34503446
auto range = ITR->getNameLoc().getSourceRange();
3451-
if (diagnoseDeclAvailability(typeDecl, range, nullptr, where, flags,
3452-
nullptr))
3447+
if (diagnoseDeclAvailability(typeDecl, range, nullptr, where, flags))
34533448
return true;
34543449
}
34553450

lib/Sema/TypeCheckAvailability.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,7 @@ diagnoseSubstitutionMapAvailability(SourceLoc loc,
233233
/// was emitted.
234234
bool diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
235235
const Expr *call, const ExportContext &where,
236-
DeclAvailabilityFlags flags = None,
237-
const ClosureExpr *singleExprClosure = nullptr);
236+
DeclAvailabilityFlags flags = None);
238237

239238
void diagnoseUnavailableOverride(ValueDecl *override,
240239
const ValueDecl *base,

0 commit comments

Comments
 (0)