Skip to content

Commit da998ba

Browse files
authored
Merge pull request #33037 from hamishknight/to-no-avail
2 parents b23a0b7 + f40cf4c commit da998ba

File tree

5 files changed

+116
-64
lines changed

5 files changed

+116
-64
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,64 +1454,6 @@ BraceStmt *swift::applyFunctionBuilderTransform(
14541454
captured.first, captured.second)));
14551455
}
14561456

1457-
/// Produce any additional syntactic diagnostics for the body of a function
1458-
/// that had a function builder applied.
1459-
static void performAddOnDiagnostics(BraceStmt *stmt, DeclContext *dc) {
1460-
class AddOnDiagnosticWalker : public ASTWalker {
1461-
SmallVector<DeclContext *, 4> dcStack;
1462-
1463-
public:
1464-
AddOnDiagnosticWalker(DeclContext *dc) {
1465-
dcStack.push_back(dc);
1466-
}
1467-
1468-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
1469-
performSyntacticExprDiagnostics(
1470-
expr, dcStack.back(), /*isExprStmt=*/false);
1471-
1472-
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
1473-
if (closure->wasSeparatelyTypeChecked()) {
1474-
dcStack.push_back(closure);
1475-
return { true, expr };
1476-
}
1477-
}
1478-
1479-
return { false, expr };
1480-
}
1481-
1482-
Expr *walkToExprPost(Expr *expr) override {
1483-
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
1484-
if (closure->wasSeparatelyTypeChecked()) {
1485-
assert(dcStack.back() == closure);
1486-
dcStack.pop_back();
1487-
}
1488-
}
1489-
1490-
return expr;
1491-
}
1492-
1493-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
1494-
performStmtDiagnostics(dcStack.back()->getASTContext(), stmt);
1495-
return { true, stmt };
1496-
}
1497-
1498-
std::pair<bool, Pattern*> walkToPatternPre(Pattern *pattern) override {
1499-
return { false, pattern };
1500-
}
1501-
1502-
bool walkToTypeLocPre(TypeLoc &typeLoc) override { return false; }
1503-
1504-
bool walkToTypeReprPre(TypeRepr *typeRepr) override { return false; }
1505-
1506-
bool walkToParameterListPre(ParameterList *params) override {
1507-
return false;
1508-
}
1509-
};
1510-
1511-
AddOnDiagnosticWalker walker(dc);
1512-
stmt->walk(walker);
1513-
}
1514-
15151457
Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
15161458
FuncDecl *func, Type builderType) {
15171459
// Pre-check the body: pre-check any expressions in it and look
@@ -1630,7 +1572,7 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
16301572
if (auto result = cs.applySolution(
16311573
solutions.front(),
16321574
SolutionApplicationTarget(func))) {
1633-
performAddOnDiagnostics(result->getFunctionBody(), func);
1575+
performSyntacticDiagnosticsForTarget(*result, /*isExprStmt*/ false);
16341576
return result->getFunctionBody();
16351577
}
16361578

lib/Sema/ConstraintSystem.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,12 @@ class SolutionApplicationTarget {
16031603
/// For a pattern initialization target, retrieve the contextual pattern.
16041604
ContextualPattern getContextualPattern() const;
16051605

1606+
/// Whether this target is for a for-in statement.
1607+
bool isForEachStmt() const {
1608+
return kind == Kind::expression &&
1609+
getExprContextualTypePurpose() == CTP_ForEachStmt;
1610+
}
1611+
16061612
/// Whether this is an initialization for an Optional.Some pattern.
16071613
bool isOptionalSomePatternInit() const {
16081614
return kind == Kind::expression &&
@@ -1659,14 +1665,12 @@ class SolutionApplicationTarget {
16591665
}
16601666

16611667
const ForEachStmtInfo &getForEachStmtInfo() const {
1662-
assert(kind == Kind::expression);
1663-
assert(expression.contextualPurpose == CTP_ForEachStmt);
1668+
assert(isForEachStmt());
16641669
return expression.forEachStmt;
16651670
}
16661671

16671672
ForEachStmtInfo &getForEachStmtInfo() {
1668-
assert(kind == Kind::expression);
1669-
assert(expression.contextualPurpose == CTP_ForEachStmt);
1673+
assert(isForEachStmt());
16701674
return expression.forEachStmt;
16711675
}
16721676

@@ -5592,6 +5596,11 @@ bool isKnownKeyPathDecl(ASTContext &ctx, ValueDecl *decl);
55925596
/// statements that could produce non-void result.
55935597
bool hasExplicitResult(ClosureExpr *closure);
55945598

5599+
/// Emit diagnostics for syntactic restrictions within a given solution
5600+
/// application target.
5601+
void performSyntacticDiagnosticsForTarget(
5602+
const SolutionApplicationTarget &target, bool isExprStmt);
5603+
55955604
} // end namespace constraints
55965605

55975606
template<typename ...Args>

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,85 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement(
19951995
return false;
19961996
}
19971997

1998+
namespace {
1999+
/// Produce any additional syntactic diagnostics for the body of a function
2000+
/// that had a function builder applied.
2001+
class FunctionSyntacticDiagnosticWalker : public ASTWalker {
2002+
SmallVector<DeclContext *, 4> dcStack;
2003+
2004+
public:
2005+
FunctionSyntacticDiagnosticWalker(DeclContext *dc) { dcStack.push_back(dc); }
2006+
2007+
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
2008+
performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false);
2009+
2010+
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
2011+
if (closure->wasSeparatelyTypeChecked()) {
2012+
dcStack.push_back(closure);
2013+
return {true, expr};
2014+
}
2015+
}
2016+
2017+
return {false, expr};
2018+
}
2019+
2020+
Expr *walkToExprPost(Expr *expr) override {
2021+
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
2022+
if (closure->wasSeparatelyTypeChecked()) {
2023+
assert(dcStack.back() == closure);
2024+
dcStack.pop_back();
2025+
}
2026+
}
2027+
2028+
return expr;
2029+
}
2030+
2031+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
2032+
performStmtDiagnostics(dcStack.back()->getASTContext(), stmt);
2033+
return {true, stmt};
2034+
}
2035+
2036+
std::pair<bool, Pattern *> walkToPatternPre(Pattern *pattern) override {
2037+
return {false, pattern};
2038+
}
2039+
2040+
bool walkToTypeLocPre(TypeLoc &typeLoc) override { return false; }
2041+
bool walkToTypeReprPre(TypeRepr *typeRepr) override { return false; }
2042+
bool walkToParameterListPre(ParameterList *params) override { return false; }
2043+
};
2044+
} // end anonymous namespace
2045+
2046+
void constraints::performSyntacticDiagnosticsForTarget(
2047+
const SolutionApplicationTarget &target, bool isExprStmt) {
2048+
auto *dc = target.getDeclContext();
2049+
switch (target.kind) {
2050+
case SolutionApplicationTarget::Kind::expression: {
2051+
// First emit diagnostics for the main expression.
2052+
performSyntacticExprDiagnostics(target.getAsExpr(), dc, isExprStmt);
2053+
2054+
// If this is a for-in statement, we also need to check the where clause if
2055+
// present.
2056+
if (target.isForEachStmt()) {
2057+
if (auto *whereExpr = target.getForEachStmtInfo().whereExpr)
2058+
performSyntacticExprDiagnostics(whereExpr, dc, /*isExprStmt*/ false);
2059+
}
2060+
return;
2061+
}
2062+
case SolutionApplicationTarget::Kind::function: {
2063+
FunctionSyntacticDiagnosticWalker walker(dc);
2064+
target.getFunctionBody()->walk(walker);
2065+
return;
2066+
}
2067+
case SolutionApplicationTarget::Kind::stmtCondition:
2068+
case SolutionApplicationTarget::Kind::caseLabelItem:
2069+
case SolutionApplicationTarget::Kind::patternBinding:
2070+
case SolutionApplicationTarget::Kind::uninitializedWrappedVar:
2071+
// Nothing to do for these.
2072+
return;
2073+
}
2074+
llvm_unreachable("Unhandled case in switch!");
2075+
}
2076+
19982077
#pragma mark High-level entry points
19992078
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20002079
Type convertType,
@@ -2096,7 +2175,7 @@ TypeChecker::typeCheckExpression(
20962175
// expression now.
20972176
if (!cs.shouldSuppressDiagnostics()) {
20982177
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
2099-
performSyntacticExprDiagnostics(result, dc, isExprStmt);
2178+
performSyntacticDiagnosticsForTarget(*resultTarget, isExprStmt);
21002179
}
21012180

21022181
resultTarget->setExpr(result);

test/Constraints/availability.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,12 @@ func test_contextual_member_with_availability() {
3434

3535
_ = Test(.foo) // Ok
3636
}
37+
38+
@available(*, unavailable)
39+
func unavailableFunction(_ x: Int) -> Bool { true } // expected-note {{'unavailableFunction' has been explicitly marked unavailable here}}
40+
41+
// SR-13260: Availability checking not working in the where clause of a for
42+
// loop.
43+
func sr13260(_ arr: [Int]) {
44+
for x in arr where unavailableFunction(x) {} // expected-error {{'unavailableFunction' is unavailable}}
45+
}

test/decl/var/function_builders_availability.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,16 @@ tuplify(true) { x in
8484
Option.best // expected-error{{'best' is only available in macOS 10.15.4 or newer}}
8585
// expected-note@-1{{add 'if #available' version check}}
8686
}
87+
88+
@available(*, unavailable)
89+
func unavailableFunc(_ x: Bool) -> Bool {} // expected-note {{'unavailableFunc' has been explicitly marked unavailable here}}
90+
91+
// SR-13260: Availability checking not working in the where clause of a for
92+
// loop.
93+
tuplify(true) { b in
94+
for x in [b] where unavailableFunc(x) { // expected-error {{'unavailableFunc' is unavailable}}
95+
""
96+
Option.best // expected-error{{'best' is only available in macOS 10.15.4 or newer}}
97+
// expected-note@-1{{add 'if #available' version check}}
98+
}
99+
}

0 commit comments

Comments
 (0)