1919#include " MiscDiagnostics.h"
2020#include " SolutionResult.h"
2121#include " TypeChecker.h"
22+ #include " TypeCheckAvailability.h"
2223#include " swift/AST/ASTVisitor.h"
2324#include " swift/AST/ASTWalker.h"
2425#include " swift/AST/NameLookup.h"
@@ -38,6 +39,24 @@ using namespace constraints;
3839
3940namespace {
4041
42+ // / Find the first #available condition within the statement condition,
43+ // / or return NULL if there isn't one.
44+ const StmtConditionElement *findAvailabilityCondition (StmtCondition stmtCond) {
45+ for (const auto &cond : stmtCond) {
46+ switch (cond.getKind ()) {
47+ case StmtConditionElement::CK_Boolean:
48+ case StmtConditionElement::CK_PatternBinding:
49+ continue ;
50+
51+ case StmtConditionElement::CK_Availability:
52+ return &cond;
53+ break ;
54+ }
55+ }
56+
57+ return nullptr ;
58+ }
59+
4160// / Visitor to classify the contents of the given closure.
4261class BuilderClosureVisitor
4362 : private StmtVisitor<BuilderClosureVisitor, VarDecl *> {
@@ -502,10 +521,20 @@ class BuilderClosureVisitor
502521 if (!cs || !thenVar || (elseChainVar && !*elseChainVar))
503522 return nullptr ;
504523
524+ // If there is a #available in the condition, the 'then' will need to
525+ // be wrapped in a call to buildAvailabilityErasure(_:), if available.
526+ Expr *thenVarRefExpr = buildVarRef (
527+ thenVar, ifStmt->getThenStmt ()->getEndLoc ());
528+ if (findAvailabilityCondition (ifStmt->getCond ()) &&
529+ builderSupports (ctx.Id_buildLimitedAvailability )) {
530+ thenVarRefExpr = buildCallIfWanted (
531+ ifStmt->getThenStmt ()->getEndLoc (), ctx.Id_buildLimitedAvailability ,
532+ { thenVarRefExpr }, { Identifier () });
533+ }
534+
505535 // Prepare the `then` operand by wrapping it to produce a chain result.
506536 Expr *thenExpr = buildWrappedChainPayload (
507- buildVarRef (thenVar, ifStmt->getThenStmt ()->getEndLoc ()),
508- payloadIndex, numPayloads, isOptional);
537+ thenVarRefExpr, payloadIndex, numPayloads, isOptional);
509538
510539 // Prepare the `else operand:
511540 Expr *elseExpr;
@@ -1054,6 +1083,35 @@ class BuilderClosureRewriter
10541083 capturedThen.first , {capturedThen.second .front ()}));
10551084 ifStmt->setThenStmt (newThen);
10561085
1086+ // Look for a #available condition. If there is one, we need to check
1087+ // that the resulting type of the "then" does refer to any types that
1088+ // are unavailable in the enclosing context.
1089+ //
1090+ // Note that this is for staging in support for
1091+ if (auto availabilityCond = findAvailabilityCondition (ifStmt->getCond ())) {
1092+ SourceLoc loc = availabilityCond->getStartLoc ();
1093+ Type thenBodyType = solution.simplifyType (
1094+ solution.getType (target.captured .second [0 ]));
1095+ thenBodyType.findIf ([&](Type type) {
1096+ auto nominal = type->getAnyNominal ();
1097+ if (!nominal)
1098+ return false ;
1099+
1100+ if (auto reason = TypeChecker::checkDeclarationAvailability (
1101+ nominal, loc, dc)) {
1102+ // Note that the problem is with the function builder, not the body.
1103+ // This is for staging only. We want to disable #available in
1104+ // function builders that don't support this operation.
1105+ ctx.Diags .diagnose (
1106+ loc, diag::function_builder_missing_limited_availability,
1107+ builderTransform.builderType );
1108+ return true ;
1109+ }
1110+
1111+ return false ;
1112+ });
1113+ }
1114+
10571115 if (auto elseBraceStmt =
10581116 dyn_cast_or_null<BraceStmt>(ifStmt->getElseStmt ())) {
10591117 // Translate the "else" branch when it's a stmt-brace.
0 commit comments