19
19
#include " MiscDiagnostics.h"
20
20
#include " SolutionResult.h"
21
21
#include " TypeChecker.h"
22
+ #include " TypeCheckAvailability.h"
22
23
#include " swift/AST/ASTVisitor.h"
23
24
#include " swift/AST/ASTWalker.h"
24
25
#include " swift/AST/NameLookup.h"
@@ -38,6 +39,24 @@ using namespace constraints;
38
39
39
40
namespace {
40
41
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
+
41
60
// / Visitor to classify the contents of the given closure.
42
61
class BuilderClosureVisitor
43
62
: private StmtVisitor<BuilderClosureVisitor, VarDecl *> {
@@ -502,10 +521,20 @@ class BuilderClosureVisitor
502
521
if (!cs || !thenVar || (elseChainVar && !*elseChainVar))
503
522
return nullptr ;
504
523
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
+
505
535
// Prepare the `then` operand by wrapping it to produce a chain result.
506
536
Expr *thenExpr = buildWrappedChainPayload (
507
- buildVarRef (thenVar, ifStmt->getThenStmt ()->getEndLoc ()),
508
- payloadIndex, numPayloads, isOptional);
537
+ thenVarRefExpr, payloadIndex, numPayloads, isOptional);
509
538
510
539
// Prepare the `else operand:
511
540
Expr *elseExpr;
@@ -1054,6 +1083,35 @@ class BuilderClosureRewriter
1054
1083
capturedThen.first , {capturedThen.second .front ()}));
1055
1084
ifStmt->setThenStmt (newThen);
1056
1085
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
+
1057
1115
if (auto elseBraceStmt =
1058
1116
dyn_cast_or_null<BraceStmt>(ifStmt->getElseStmt ())) {
1059
1117
// Translate the "else" branch when it's a stmt-brace.
0 commit comments