@@ -2767,7 +2767,6 @@ class ExprAvailabilityWalker : public ASTWalker {
2767
2767
ASTContext &Context;
2768
2768
MemberAccessContext AccessContext = MemberAccessContext::Getter;
2769
2769
SmallVector<const Expr *, 16 > ExprStack;
2770
- SmallVector<ClosureExpr *, 4 > singleExprClosureStack;
2771
2770
const ExportContext &Where;
2772
2771
2773
2772
public:
@@ -2848,16 +2847,20 @@ class ExprAvailabilityWalker : public ASTWalker {
2848
2847
E->getLoc (), Where);
2849
2848
}
2850
2849
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
+ }
2861
2864
}
2862
2865
2863
2866
return visitChildren ();
@@ -2867,14 +2870,6 @@ class ExprAvailabilityWalker : public ASTWalker {
2867
2870
assert (ExprStack.back () == E);
2868
2871
ExprStack.pop_back ();
2869
2872
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
-
2878
2873
return E;
2879
2874
}
2880
2875
@@ -2885,10 +2880,7 @@ class ExprAvailabilityWalker : public ASTWalker {
2885
2880
// contain statements and declarations. We need to walk them recursively,
2886
2881
// since these availability for these statements is not diagnosed from
2887
2882
// 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 );
2892
2884
return std::make_pair (false , S);
2893
2885
}
2894
2886
@@ -3007,6 +2999,21 @@ class ExprAvailabilityWalker : public ASTWalker {
3007
2999
walkInContext (E, E->getSubExpr (), MemberAccessContext::InOut);
3008
3000
}
3009
3001
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
+
3010
3017
// / Walk the given expression in the member access context.
3011
3018
void walkInContext (Expr *baseExpr, Expr *E,
3012
3019
MemberAccessContext AccessContext) {
@@ -3068,7 +3075,7 @@ class ExprAvailabilityWalker : public ASTWalker {
3068
3075
Flags &= DeclAvailabilityFlag::ForInout;
3069
3076
Flags |= DeclAvailabilityFlag::ContinueOnPotentialUnavailability;
3070
3077
if (diagnoseDeclAvailability (D, ReferenceRange, /* call*/ nullptr , Where,
3071
- Flags, nullptr ))
3078
+ Flags))
3072
3079
return ;
3073
3080
}
3074
3081
};
@@ -3091,9 +3098,7 @@ bool ExprAvailabilityWalker::diagnoseDeclRefAvailability(
3091
3098
return true ;
3092
3099
}
3093
3100
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);
3097
3102
3098
3103
if (R.isValid ()) {
3099
3104
if (diagnoseSubstitutionMapAvailability (R.Start , declRef.getSubstitutions (),
@@ -3110,8 +3115,7 @@ bool ExprAvailabilityWalker::diagnoseDeclRefAvailability(
3110
3115
// / Returns true if a diagnostic was emitted, false otherwise.
3111
3116
static bool
3112
3117
diagnoseDeclUnavailableFromAsync (const ValueDecl *D, SourceRange R,
3113
- const Expr *call, const ExportContext &Where,
3114
- const ClosureExpr *singleExprClosure) {
3118
+ const Expr *call, const ExportContext &Where) {
3115
3119
// FIXME: I don't think this is right, but I don't understand the issue well
3116
3120
// enough to fix it properly. If the decl context is an abstract
3117
3121
// closure, we need it to have a type assigned to it before we can
@@ -3140,15 +3144,8 @@ diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
3140
3144
return false ;
3141
3145
}
3142
3146
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 ())
3152
3149
return false ;
3153
3150
if (!D->getAttrs ().hasAttribute <UnavailableFromAsyncAttr>())
3154
3151
return false ;
@@ -3168,8 +3165,7 @@ diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
3168
3165
bool swift::diagnoseDeclAvailability (const ValueDecl *D, SourceRange R,
3169
3166
const Expr *call,
3170
3167
const ExportContext &Where,
3171
- DeclAvailabilityFlags Flags,
3172
- const ClosureExpr *singleExprClosure) {
3168
+ DeclAvailabilityFlags Flags) {
3173
3169
assert (!Where.isImplicit ());
3174
3170
3175
3171
// Generic parameters are always available.
@@ -3197,7 +3193,7 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
3197
3193
if (diagnoseExplicitUnavailability (D, R, Where, call, Flags))
3198
3194
return true ;
3199
3195
3200
- if (diagnoseDeclUnavailableFromAsync (D, R, call, Where, singleExprClosure ))
3196
+ if (diagnoseDeclUnavailableFromAsync (D, R, call, Where))
3201
3197
return true ;
3202
3198
3203
3199
// Make sure not to diagnose an accessor's deprecation if we already
@@ -3448,8 +3444,7 @@ class TypeReprAvailabilityWalker : public ASTWalker {
3448
3444
bool checkComponentIdentTypeRepr (ComponentIdentTypeRepr *ITR) {
3449
3445
if (auto *typeDecl = ITR->getBoundDecl ()) {
3450
3446
auto range = ITR->getNameLoc ().getSourceRange ();
3451
- if (diagnoseDeclAvailability (typeDecl, range, nullptr , where, flags,
3452
- nullptr ))
3447
+ if (diagnoseDeclAvailability (typeDecl, range, nullptr , where, flags))
3453
3448
return true ;
3454
3449
}
3455
3450
0 commit comments