@@ -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
27732772public:
@@ -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.
31113116static bool
31123117diagnoseDeclUnavailableFromAsync (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,
31683165bool 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
0 commit comments