Skip to content

Commit 5669985

Browse files
authored
Merge pull request #29419 from DougGregor/function-builder-if-available
[Function builders] Add support for "if #available".
2 parents 449651a + 23615ba commit 5669985

File tree

4 files changed

+141
-46
lines changed

4 files changed

+141
-46
lines changed

lib/Sema/BuilderTransform.cpp

+6-46
Original file line numberDiff line numberDiff line change
@@ -324,27 +324,11 @@ class BuilderClosureVisitor
324324
CONTROL_FLOW_STMT(Yield)
325325
CONTROL_FLOW_STMT(Defer)
326326

327-
/// Whether we can handle all of the conditions for this statement.
328-
static bool canHandleStmtConditions(StmtCondition condition) {
329-
for (const auto &element : condition) {
330-
switch (element.getKind()) {
331-
case StmtConditionElement::CK_Boolean:
332-
continue;
333-
334-
case StmtConditionElement::CK_PatternBinding:
335-
case StmtConditionElement::CK_Availability:
336-
return false;
337-
}
338-
}
339-
340-
return true;
341-
}
342-
343327
static bool isBuildableIfChainRecursive(IfStmt *ifStmt,
344328
unsigned &numPayloads,
345329
bool &isOptional) {
346330
// Check whether we can handle the conditional.
347-
if (!canHandleStmtConditions(ifStmt->getCond()))
331+
if (!ConstraintSystem::canGenerateConstraints(ifStmt->getCond()))
348332
return false;
349333

350334
// The 'then' clause contributes a payload.
@@ -470,38 +454,12 @@ class BuilderClosureVisitor
470454
payloadIndex + 1, numPayloads, isOptional);
471455
}
472456

473-
// Condition must convert to Bool.
474-
// FIXME: This should be folded into constraint generation for conditions.
475-
auto boolDecl = ctx.getBoolDecl();
476-
if (!boolDecl) {
457+
// Generate constraints for the conditions.
458+
if (cs->generateConstraints(ifStmt->getCond(), dc)) {
477459
hadError = true;
478460
return nullptr;
479461
}
480462

481-
// Generate constraints for the conditions.
482-
for (const auto &condElement : ifStmt->getCond()) {
483-
switch (condElement.getKind()) {
484-
case StmtConditionElement::CK_Boolean: {
485-
Expr *condExpr = condElement.getBoolean();
486-
condExpr = cs->generateConstraints(condExpr, dc);
487-
if (!condExpr) {
488-
hadError = true;
489-
return nullptr;
490-
}
491-
492-
cs->addConstraint(ConstraintKind::Conversion,
493-
cs->getType(condExpr),
494-
boolDecl->getDeclaredType(),
495-
cs->getConstraintLocator(condExpr));
496-
continue;
497-
}
498-
499-
case StmtConditionElement::CK_PatternBinding:
500-
case StmtConditionElement::CK_Availability:
501-
llvm_unreachable("unhandled statement condition");
502-
}
503-
}
504-
505463
// The operand should have optional type if we had optional results,
506464
// so we just need to call `buildIf` now, since we're at the top level.
507465
if (isOptional && isTopLevel) {
@@ -873,6 +831,9 @@ class BuilderClosureRewriter
873831
auto condition = ifStmt->getCond();
874832
for (auto &condElement : condition) {
875833
switch (condElement.getKind()) {
834+
case StmtConditionElement::CK_Availability:
835+
continue;
836+
876837
case StmtConditionElement::CK_Boolean: {
877838
auto condExpr = condElement.getBoolean();
878839
auto finalCondExpr = rewriteExpr(condExpr);
@@ -888,7 +849,6 @@ class BuilderClosureRewriter
888849
}
889850

890851
case StmtConditionElement::CK_PatternBinding:
891-
case StmtConditionElement::CK_Availability:
892852
llvm_unreachable("unhandled statement condition");
893853
}
894854
}

lib/Sema/CSGen.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -3798,6 +3798,57 @@ Type ConstraintSystem::generateConstraints(Pattern *pattern,
37983798
return cg.getTypeForPattern(pattern, locator);
37993799
}
38003800

3801+
bool ConstraintSystem::canGenerateConstraints(StmtCondition condition) {
3802+
for (const auto &element : condition) {
3803+
switch (element.getKind()) {
3804+
case StmtConditionElement::CK_Availability:
3805+
case StmtConditionElement::CK_Boolean:
3806+
continue;
3807+
3808+
case StmtConditionElement::CK_PatternBinding:
3809+
return false;
3810+
}
3811+
}
3812+
3813+
return true;
3814+
}
3815+
3816+
bool ConstraintSystem::generateConstraints(StmtCondition condition,
3817+
DeclContext *dc) {
3818+
// FIXME: This should be folded into constraint generation for conditions.
3819+
auto boolDecl = getASTContext().getBoolDecl();
3820+
if (!boolDecl) {
3821+
return true;
3822+
}
3823+
3824+
for (const auto &condElement : condition) {
3825+
switch (condElement.getKind()) {
3826+
case StmtConditionElement::CK_Availability:
3827+
// Nothing to do here.
3828+
continue;
3829+
3830+
case StmtConditionElement::CK_Boolean: {
3831+
Expr *condExpr = condElement.getBoolean();
3832+
condExpr = generateConstraints(condExpr, dc);
3833+
if (!condExpr) {
3834+
return true;
3835+
}
3836+
3837+
addConstraint(ConstraintKind::Conversion,
3838+
getType(condExpr),
3839+
boolDecl->getDeclaredType(),
3840+
getConstraintLocator(condExpr));
3841+
continue;
3842+
}
3843+
3844+
case StmtConditionElement::CK_PatternBinding:
3845+
llvm_unreachable("unhandled statement condition");
3846+
}
3847+
}
3848+
3849+
return false;
3850+
}
3851+
38013852
void ConstraintSystem::optimizeConstraints(Expr *e) {
38023853
if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks)
38033854
return;

lib/Sema/ConstraintSystem.h

+10
Original file line numberDiff line numberDiff line change
@@ -3080,6 +3080,16 @@ class ConstraintSystem {
30803080
/// \returns a possibly-sanitized initializer, or null if an error occurred.
30813081
Type generateConstraints(Pattern *P, ConstraintLocatorBuilder locator);
30823082

3083+
/// Determines whether we can generate constraints for this statement
3084+
/// condition.
3085+
static bool canGenerateConstraints(StmtCondition condition);
3086+
3087+
/// Generate constraints for a statement condition.
3088+
///
3089+
/// \returns true if there was an error in constraint generation, false
3090+
/// if generation succeeded.
3091+
bool generateConstraints(StmtCondition condition, DeclContext *dc);
3092+
30833093
/// Generate constraints for a given set of overload choices.
30843094
///
30853095
/// \param constraints The container of generated constraint choices.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %target-typecheck-verify-swift -target x86_64-apple-macosx10.50
2+
3+
// REQUIRES: OS=macosx
4+
5+
enum Either<T,U> {
6+
case first(T)
7+
case second(U)
8+
}
9+
10+
@_functionBuilder
11+
struct TupleBuilder {
12+
static func buildBlock<T1>(_ t1: T1) -> (T1) {
13+
return (t1)
14+
}
15+
16+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
17+
return (t1, t2)
18+
}
19+
20+
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
21+
-> (T1, T2, T3) {
22+
return (t1, t2, t3)
23+
}
24+
25+
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
26+
-> (T1, T2, T3, T4) {
27+
return (t1, t2, t3, t4)
28+
}
29+
30+
static func buildBlock<T1, T2, T3, T4, T5>(
31+
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
32+
) -> (T1, T2, T3, T4, T5) {
33+
return (t1, t2, t3, t4, t5)
34+
}
35+
36+
static func buildDo<T>(_ value: T) -> T { return value }
37+
static func buildIf<T>(_ value: T?) -> T? { return value }
38+
39+
static func buildEither<T,U>(first value: T) -> Either<T,U> {
40+
return .first(value)
41+
}
42+
static func buildEither<T,U>(second value: U) -> Either<T,U> {
43+
return .second(value)
44+
}
45+
}
46+
47+
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) {
48+
print(body(cond))
49+
}
50+
51+
@available(OSX, introduced: 10.9)
52+
func globalFuncAvailableOn10_9() -> Int { return 9 }
53+
54+
@available(OSX, introduced: 10.51)
55+
func globalFuncAvailableOn10_51() -> Int { return 10 }
56+
57+
@available(OSX, introduced: 10.52)
58+
func globalFuncAvailableOn10_52() -> Int { return 11 }
59+
60+
tuplify(true) { cond in
61+
globalFuncAvailableOn10_9()
62+
if #available(OSX 10.51, *) {
63+
globalFuncAvailableOn10_51()
64+
tuplify(false) { cond2 in
65+
if cond, #available(OSX 10.52, *) {
66+
cond2
67+
globalFuncAvailableOn10_52()
68+
} else {
69+
globalFuncAvailableOn10_52() // expected-error{{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
70+
// expected-note@-1{{add 'if #available' version check}}
71+
}
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)