diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 317ec7ff95eb0..888cf00e55f34 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7862,6 +7862,13 @@ ERROR(atomics_ordering_must_be_constant, none, "ordering argument must be a static method or property of %0", (Identifier)) +//------------------------------------------------------------------------------ +// MARK: SwiftUI +//------------------------------------------------------------------------------ + +WARNING(swiftui_arg_must_be_integer_literal, none, + "argument must be an integer literal", ()) + //------------------------------------------------------------------------------ // MARK: access notes //------------------------------------------------------------------------------ diff --git a/include/swift/AST/SemanticAttrs.def b/include/swift/AST/SemanticAttrs.def index 98ada5ecb7a2e..8b7662c08ad2f 100644 --- a/include/swift/AST/SemanticAttrs.def +++ b/include/swift/AST/SemanticAttrs.def @@ -96,6 +96,8 @@ SEMANTICS_ATTR(OSLOG_REQUIRES_CONSTANT_ARGUMENTS, "oslog.requires_constant_argum SEMANTICS_ATTR(OSLOG_LOG_WITH_LEVEL, "oslog.log_with_level") SEMANTICS_ATTR(ATOMICS_REQUIRES_CONSTANT_ORDERINGS, "atomics.requires_constant_orderings") +SEMANTICS_ATTR(SWIFT_UI_REQUIRES_CONSTANT_RANGE, "swiftui.requires_constant_range") + SEMANTICS_ATTR(TYPE_CHECKER_OPEN_EXISTENTIAL, "typechecker._openExistential(_:do:)") SEMANTICS_ATTR(TYPE_CHECKER_TYPE, "typechecker.type(of:)") SEMANTICS_ATTR(TYPE_CHECKER_WITHOUT_ACTUALLY_ESCAPING, "typechecker.withoutActuallyEscaping(_:do:)") diff --git a/lib/Sema/ConstantnessSemaDiagnostics.cpp b/lib/Sema/ConstantnessSemaDiagnostics.cpp index 9357f21070816..df10b5cdfea96 100644 --- a/lib/Sema/ConstantnessSemaDiagnostics.cpp +++ b/lib/Sema/ConstantnessSemaDiagnostics.cpp @@ -76,6 +76,8 @@ static bool isParamRequiredToBeConstant(AbstractFunctionDecl *funcDecl, ParamDec nominal = paramType->getNominalOrBoundGenericNominal(); return !nominal || !isOSLogDynamicObject(nominal); } + if (hasSemanticsAttr(funcDecl, semantics::SWIFT_UI_REQUIRES_CONSTANT_RANGE)) + return param->getParameterName().str() == "data"; if (!hasSemanticsAttr(funcDecl, semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS)) return false; @@ -245,6 +247,12 @@ static void diagnoseError(Expr *errorExpr, const ASTContext &astContext, return; } + if (hasSemanticsAttr(funcDecl, + semantics::SWIFT_UI_REQUIRES_CONSTANT_RANGE)) { + diags.diagnose(errorLoc, diag::swiftui_arg_must_be_integer_literal); + return; + } + // Diagnose os_log specific errors here. // Diagnose primitive stdlib types. diff --git a/test/Sema/diag_constantness_check_swift_ui.swift b/test/Sema/diag_constantness_check_swift_ui.swift new file mode 100644 index 0000000000000..ddd35fcdcbadc --- /dev/null +++ b/test/Sema/diag_constantness_check_swift_ui.swift @@ -0,0 +1,34 @@ +// RUN: %target-typecheck-verify-swift + +// Replicating the SwiftUI framework `ForEach` from the SDK +public struct ForEach where Data : Swift.RandomAccessCollection, ID: Swift.Hashable { + public var data: Data + public var content: (Data.Element) -> Content +} + +public protocol View {} +public struct AView: View {} + +extension ForEach where Content : View { + public init(_ data: Data, id: Swift.KeyPath, content: @escaping (Data.Element) -> Content) { + self.data = data + self.content = content + } +} + +extension ForEach where Data == Swift.Range, ID == Swift.Int, Content : View { + @_semantics("swiftui.requires_constant_range") public init(_ data: Swift.Range, content: @escaping (Swift.Int) -> Content) +} + + +func testSwiftUIForEachInvalid() { + let notReallyConstant = 10 + _ = ForEach(0..