diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index b6fb85133b90c..06cba96996f96 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1206,6 +1206,7 @@ struct DynamicCallableMethods { /// Describes the target to which a constraint system's solution can be /// applied. class SolutionApplicationTarget { +public: enum class Kind { expression, function, @@ -1213,6 +1214,7 @@ class SolutionApplicationTarget { caseLabelItem, } kind; +private: union { struct { /// The expression being type-checked. @@ -1418,6 +1420,12 @@ class SolutionApplicationTarget { /// For a pattern initialization target, retrieve the contextual pattern. ContextualPattern getContextualPattern() const; + /// Whether this target is for a for-in statement. + bool isForEachStmt() const { + return kind == Kind::expression && + getExprContextualTypePurpose() == CTP_ForEachStmt; + } + /// Whether this is an initialization for an Optional.Some pattern. bool isOptionalSomePatternInit() const { return kind == Kind::expression && @@ -1466,14 +1474,12 @@ class SolutionApplicationTarget { } const ForEachStmtInfo &getForEachStmtInfo() const { - assert(kind == Kind::expression); - assert(expression.contextualPurpose == CTP_ForEachStmt); + assert(isForEachStmt()); return expression.forEachStmt; } ForEachStmtInfo &getForEachStmtInfo() { - assert(kind == Kind::expression); - assert(expression.contextualPurpose == CTP_ForEachStmt); + assert(isForEachStmt()); return expression.forEachStmt; } @@ -5284,6 +5290,11 @@ bool isKnownKeyPathDecl(ASTContext &ctx, ValueDecl *decl); /// statements that could produce non-void result. bool hasExplicitResult(ClosureExpr *closure); +/// Emit diagnostics for syntactic restrictions within a given solution +/// application target. +void performSyntacticDiagnosticsForTarget( + const SolutionApplicationTarget &target, bool isExprStmt); + } // end namespace constraints template diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 47e0795f5ac4d..5787e0c0b485d 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2008,6 +2008,31 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement( return false; } +void constraints::performSyntacticDiagnosticsForTarget( + const SolutionApplicationTarget &target, bool isExprStmt) { + auto *dc = target.getDeclContext(); + switch (target.kind) { + case SolutionApplicationTarget::Kind::expression: { + // First emit diagnostics for the main expression. + performSyntacticExprDiagnostics(target.getAsExpr(), dc, isExprStmt); + + // If this is a for-in statement, we also need to check the where clause if + // present. + if (target.isForEachStmt()) { + if (auto *whereExpr = target.getForEachStmtInfo().whereExpr) + performSyntacticExprDiagnostics(whereExpr, dc, /*isExprStmt*/ false); + } + return; + } + case SolutionApplicationTarget::Kind::function: + case SolutionApplicationTarget::Kind::stmtCondition: + case SolutionApplicationTarget::Kind::caseLabelItem: + // Nothing to do for these. + return; + } + llvm_unreachable("Unhandled case in switch!"); +} + #pragma mark High-level entry points Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, TypeLoc convertType, @@ -2122,7 +2147,7 @@ TypeChecker::typeCheckExpression( // expression now. if (!cs.shouldSuppressDiagnostics()) { bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt); - performSyntacticExprDiagnostics(result, dc, isExprStmt); + performSyntacticDiagnosticsForTarget(*resultTarget, isExprStmt); } resultTarget->setExpr(result); diff --git a/test/Constraints/availability.swift b/test/Constraints/availability.swift index 5968441c4bc07..2fe93b9f20286 100644 --- a/test/Constraints/availability.swift +++ b/test/Constraints/availability.swift @@ -34,3 +34,12 @@ func test_contextual_member_with_availability() { _ = Test(.foo) // Ok } + +@available(*, unavailable) +func unavailableFunction(_ x: Int) -> Bool { true } // expected-note {{'unavailableFunction' has been explicitly marked unavailable here}} + +// SR-13260: Availability checking not working in the where clause of a for +// loop. +func sr13260(_ arr: [Int]) { + for x in arr where unavailableFunction(x) {} // expected-error {{'unavailableFunction' is unavailable}} +}