From 5dab0d1c5e96b9069c707b71d1855088dd7b288f Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 14 Jul 2026 16:19:56 +0100 Subject: [PATCH 01/10] [Sema] Only constant-fold integer literal expressions With LiteralExpressions enabled, the integer constant-folder was invoked on non-integer enum raw values (String/Float), non-integer @section/@const constants, and OSLog section strings, emitting a spurious "not supported in a literal expression". Gate folding on a stdlib integer type so non-integer literals are used as written, and reject magic-identifier / non-literal enum raw values before RawValueKey (which only handles Int/Float/String/Bool) instead of tripping its assertion. --- lib/AST/Decl.cpp | 10 ++++- lib/Sema/LiteralExpressionFolding.cpp | 7 +++- lib/Sema/TypeCheckDecl.cpp | 39 ++++++++++++++++--- .../NonIntegerRawValues.swift | 32 +++++++++++++++ 4 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 test/LiteralExpressions/NonIntegerRawValues.swift diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3ead6c09e9522..121338a93abb4 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2954,8 +2954,14 @@ VarDecl *PatternBindingDecl::getAnchoringVarDecl(unsigned i) const { bool PatternBindingDecl::hasSingleVarConstantFoldedInit() const { auto *singleVar = getSingleVar(); - return singleVar && singleVar->isConstValue() && - getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions); + if (!singleVar || !singleVar->isConstValue() || + !getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions)) + return false; + // Only stdlib integer constants participate in literal-expression folding. + // Other constant initializers (tuples, arrays, strings, ...) are left as + // written and must not be routed through the integer constant-folder. + Type type = singleVar->getInterfaceType(); + return type && type->isStdlibInteger(); } Expr *PatternBindingDecl::getExecutableInit(unsigned i) const { diff --git a/lib/Sema/LiteralExpressionFolding.cpp b/lib/Sema/LiteralExpressionFolding.cpp index 2cc9026121af5..a2a25c0ad0351 100644 --- a/lib/Sema/LiteralExpressionFolding.cpp +++ b/lib/Sema/LiteralExpressionFolding.cpp @@ -649,7 +649,12 @@ Expr *swift::foldLiteralExpression(const Expr *expr, ASTContext *ctx) { Expr *ConstantFoldExpression::evaluate(Evaluator &evaluator, const Expr *expr, ASTContext *ctx) const { - if (ctx->LangOpts.hasFeature(Feature::LiteralExpressions)) { + // Only integer literal expressions are folded. Expressions of other types + // (non-integer literals, tuples, arrays, ...) are returned unchanged so they + // are never routed through the integer constant-folder, which would reject + // them with a spurious diagnostic. + if (ctx->LangOpts.hasFeature(Feature::LiteralExpressions) && + expr->getType() && expr->getType()->isStdlibInteger()) { ConstantFolder folder(*ctx); if (auto result = folder.fold(expr)) return result; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 798f8a428af6e..2bae7628991a3 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -78,6 +78,15 @@ using namespace swift; namespace { +/// Whether \p expr is a literal of a kind that can serve as an enum raw value +/// (i.e. one handled by \c RawValueKey). This excludes literals such as +/// \c #file and other magic identifiers, regex literals, and object literals, +/// which type-check in some contexts but are not valid raw values. +static bool isValidEnumRawValueLiteral(const LiteralExpr *expr) { + return isa(expr) || isa(expr) || + isa(expr) || isa(expr); +} + /// Used during enum raw value checking to identify duplicate raw values. /// Character, string, float, and integer literals are all keyed by value. /// Float and integer literals are additionally keyed by numeric equivalence. @@ -1282,20 +1291,29 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { } } + // Literal expressions are folded only for integer raw types; other raw + // types (String, Float, ...) use the written literal directly. Gating on + // an integer raw type keeps non-integer initializers from being routed + // through the integer constant-folder, which would reject them. bool literalExprEnabled = ED->getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions); - // We must constant-fold the expression here to reduce it to - // a LiteralExpr so that: - // 1. We validate the expression *is* foldable down to a constant + bool foldIntegerRawValue = + literalExprEnabled && rawTy && rawTy->isStdlibInteger(); + // We must reduce the expression to a LiteralExpr here so that: + // 1. We validate the expression *is* a usable raw value. // 2. We can use it to compute the next automatic raw value expression. - prevValue = literalExprEnabled + prevValue = foldIntegerRawValue ? dyn_cast( foldLiteralExpression(value, &ED->getASTContext())) : dyn_cast(value); if (!prevValue) { + // When the feature is disabled, non-literal raw values are already + // rejected during parsing; only diagnose here when it is enabled. if (literalExprEnabled && value) ED->getASTContext().Diags.diagnose( - value->getLoc(), diag::nonliteral_int_expr_enum_case_raw_value); + value->getLoc(), foldIntegerRawValue + ? diag::nonliteral_int_expr_enum_case_raw_value + : diag::nonliteral_enum_case_raw_value); continue; } @@ -1319,6 +1337,17 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit() ? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc(); + + // Only Integer/Float/String/Bool literals can serve as raw values. Reject + // any other literal -- magic identifiers such as #file/#line, regex + // literals, object literals -- here, since RawValueKey below only handles + // those four kinds. + if (!isValidEnumRawValueLiteral(prevValue)) { + Diags.diagnose(diagLoc, diag::nonliteral_enum_case_raw_value); + prevValue = nullptr; + continue; + } + // Check that the raw value is unique. RawValueKey key{prevValue}; RawValueSource source{elt, lastExplicitValueElt}; diff --git a/test/LiteralExpressions/NonIntegerRawValues.swift b/test/LiteralExpressions/NonIntegerRawValues.swift new file mode 100644 index 0000000000000..1bd76c561157d --- /dev/null +++ b/test/LiteralExpressions/NonIntegerRawValues.swift @@ -0,0 +1,32 @@ +// Regression test for the LiteralExpressions constant-folder: only integer +// literal expressions may be folded. Non-integer enum raw values and +// non-integer @section constants must be used as written rather than routed +// through the integer constant-folder (which would reject them with a spurious +// diagnostic), and non-literal / magic-identifier raw values must be rejected +// rather than tripping an assertion in RawValueKey. + +// REQUIRES: swift_feature_LiteralExpressions +// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unrelated -enable-experimental-feature LiteralExpressions + +// Non-integer raw values are accepted as written (not folded). +enum StringEnum: String { case a = "foo"; case b = "bar" } +enum DoubleEnum: Double { case a = 1.5; case b = 2.5 } + +// Integer raw values are still folded from literal expressions. +enum IntEnum: Int { case a = 2 + 2; case b; case c = 1 << 3 } + +// Non-integer @section constants are accepted as written. +@section("mysection") let tupleGlobal: (UInt8, UInt8, UInt8) = (1, 2, 3) +@section("mysection") let boolTuple: (Bool, Bool) = (true, false) +// Integer @section constants are still folded. +@section("mysection") let intGlobal: Int = 2 * 4096 + +// Magic identifiers, calls, and other non-raw-value expressions are rejected +// with a clear diagnostic (and must not crash). +enum MagicEnum: String { + case a = #file // expected-error {{raw value for enum case must be a literal}} +} +func nonConst() -> String { "x" } +enum CallEnum: String { + case a = nonConst() // expected-error {{raw value for enum case must be a literal}} +} From 93a552fe2d0b9bb7e5d59d33b1da99b70fbecab1 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 14 Jul 2026 17:39:02 +0100 Subject: [PATCH 02/10] [Parse] Fix generic-argument recognition of function types `canParseGenericArguments` unconditionally skipped a parenthesized group at the start of a generic argument, so a function type like `(Int, Int) -> Bool` left its `->` dangling and the argument list's closing `>` was never matched. With LiteralExpressions enabled by default this rejected valid code such as `Foo<(Int, Int) -> Bool>`. Treat the parentheses as a value expression only when immediately followed by `,` or `>`; otherwise parse a type, matching the disambiguation already used in `parseTypeOrValue`. --- lib/Parse/ParseType.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 80560d3d66fd4..4b0d399b08fd6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1733,10 +1733,21 @@ bool Parser::canParseGenericArguments() { } do { - if (Context.LangOpts.hasFeature(Feature::LiteralExpressions) && - Tok.is(tok::l_paren)) + // A generic argument may be a parenthesized value expression such as + // '(1 + 2)'. Treat a parenthesized group as a value expression only when + // it is immediately followed by ',' or '>'; otherwise parse it as a type + // so that parenthesized and function types like '(Int, Int) -> Bool' are + // still recognized. + bool parsedValueExpr = false; + if (Tok.is(tok::l_paren)) { + CancellableBacktrackingScope backtrack(*this); skipSingle(); - else if (!canParseType()) + if (Tok.is(tok::comma) || startsWithGreater(Tok)) { + backtrack.cancelBacktrack(); + parsedValueExpr = true; + } + } + if (!parsedValueExpr && !canParseType()) return false; // Parse the comma, if the list continues. From 7741fbc82efa921419e185a797c0c9c21d99611c Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 15 Jul 2026 09:32:24 +0100 Subject: [PATCH 03/10] [Literal Expressions] Fold sequences in the generic-argument TypeExpr simplifier A composition like 'P1 & P2' inside a parenthesized generic argument is parsed as an unfolded SequenceExpr. GenericArgumentSimplifierWalker never folded it into a BinaryExpr, so it wasn't recognized as a composition type. Fold sequences here, mirroring the main PreCheckExpression walker. --- lib/Sema/PreCheckTarget.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/Sema/PreCheckTarget.cpp b/lib/Sema/PreCheckTarget.cpp index 8cded7731667e..3f4b75378cb41 100644 --- a/lib/Sema/PreCheckTarget.cpp +++ b/lib/Sema/PreCheckTarget.cpp @@ -2904,6 +2904,20 @@ TypeExpr *TypeChecker::simplifyGenericArgumentTypeExpr(DeclContext *DC, return MacroWalking::ArgumentsAndExpansion; } PreWalkResult walkToExprPre(Expr *expr) override { + // Fold sequence expressions (e.g. 'P1 & P2') into BinaryExprs so that the + // composition / type-sugar folding in walkToExprPost can recognize them. + // This mirrors the main PreCheckExpression walker, without it a + // parenthesized composition that was parsed as a value expression (such + // as a generic argument '(P1 & P2, ...)') does not simplify to a type. + if (auto *seqExpr = dyn_cast(expr)) { + auto *folded = TypeChecker::foldSequence(seqExpr, DC); + folded = folded->walk(*this); + if (!folded) + return Action::Stop(); + // Already walked. + return Action::SkipNode(folded); + } + // Resolve unqualified name references if (auto *unresolved = dyn_cast(expr)) { auto *resolved = TypeChecker::resolveDeclRefExpr(unresolved, DC); From aa0c485f06205164c227e35a68d7766b2e3eea63 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 15 Jul 2026 12:49:32 +0100 Subject: [PATCH 04/10] [Parse][Literal Expressions] Parse generic arguments with opaque 'some' types as types With LiteralExpressions enabled, a parenthesized generic argument that could start a value expression (e.g. `Foo<(2 + 3)>`) is routed to expression parsing. This is not the correct thing to do for for `Foo<(Int, some P)>`, because then the `some P` is contained in a GenericArgumentExprTypeRepr. `any`/`each` and `P & Q` compositions recover fine from that, but `some` can't: its implicit OpaqueTypeDecl is collected by walking the enclosing declaration's TypeRepr tree (OpaqueResultTypeRequest), so an opaque type inside an expression is never seen, and resolution fails with "'some' types are only permitted in properties, subscripts, and functions." When a parenthesized generic argument contains an opaque `some` type, parse the group as a type. --- include/swift/Parse/Parser.h | 6 ++++++ lib/Parse/ParseType.cpp | 31 +++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index bdb1a047b5587..ce57af685570d 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1761,6 +1761,12 @@ class Parser { bool canParseGenericArguments(); bool canParseGenericValueLiteral(); + /// Assuming the parser is positioned at the opening '(' of a generic argument + /// that would otherwise be parsed as a value expression, check if the + /// parenthesized group contains an opaque 'some' type that requires it to be + /// parsed as a type instead. + bool parenGenericArgumentContainsTypeOnlySyntax(); + bool canParseTypedPattern(); /// Returns true if a qualified declaration name base type can be parsed. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 4b0d399b08fd6..f964a31af4e7b 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1621,6 +1621,13 @@ ParserResult Parser::parseTypeOrValue(Diag<> MessageID, shouldParseValueExpr = true; } + // A parenthesized expression that contains type-only syntax such as an opaque + // 'some' type must be parsed as a type, not a value expression: opaque types + // have to appear as TypeReprs in the enclosing declaration. + if (shouldParseValueExpr && Tok.is(tok::l_paren) && + parenGenericArgumentContainsTypeOnlySyntax()) + shouldParseValueExpr = false; + if (shouldParseValueExpr) { // Ensure that constituent references get parsed as declaration references, // not type references. @@ -1633,9 +1640,29 @@ ParserResult Parser::parseTypeOrValue(Diag<> MessageID, } return makeParserResult( new (Context) GenericArgumentExprTypeRepr(expr.get(), &Context)); - } else { - return parseType(MessageID, reason); } + return parseType(MessageID, reason); +} + +bool Parser::parenGenericArgumentContainsTypeOnlySyntax() { + assert(Tok.is(tok::l_paren) && "not at a parenthesized generic argument"); + BacktrackingScope backtrack(*this); + unsigned depth = 0; + do { + // An opaque 'some' type can only appear as a type, never as part of a + // value expression. + if (Tok.isContextualKeyword("some")) { + BacktrackingScope probe(*this); + if (canParseType()) + return true; + } + if (Tok.isAny(tok::l_paren, tok::l_square, tok::l_brace)) + ++depth; + else if (Tok.isAny(tok::r_paren, tok::r_square, tok::r_brace)) + --depth; + consumeToken(); + } while (depth > 0 && Tok.isNot(tok::eof)); + return false; } bool Parser::canParseGenericValueLiteral() { From 896dd21c7a97c9070c8b07c1b4896a8f460b21c4 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 17 Jul 2026 13:43:10 +0100 Subject: [PATCH 05/10] [Sema] Recover from non-literal enum raw values With LiteralExpressions on by default, a raw value that cannot be a literal (regex, #file, object literal, or a non-foldable expression such as a closure or 'await') is diagnosed and replaced with an automatic value, so the enum still conforms to RawRepresentable rather than feeding a non-literal expression to RawRepresentable derivation, which asserted in cloneRawLiteralExpr. Permit clearing a raw value via `setRawValueExpr(nullptr)`. --- lib/AST/Decl.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 38 ++++++++++++++++++- test/Parse/enum.swift | 4 +- ...um_raw_representable_object_literals.swift | 6 +-- test/decl/enum/enumtest.swift | 2 +- test/expr/unary/async_await.swift | 2 +- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 121338a93abb4..88a173fd39e7b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -12276,7 +12276,7 @@ LiteralExpr *EnumElementDecl::getRawValueExpr() const { } void EnumElementDecl::setRawValueExpr(Expr *e) { - assert((!RawValueExpr || e == RawValueExpr || e->getType()) && + assert((!RawValueExpr || e == RawValueExpr || !e || e->getType()) && "Illegal mutation of raw value expr"); RawValueExpr = e; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2bae7628991a3..3859871626ca1 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1254,6 +1254,24 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { if (elt->isInvalid()) continue; + // A raw value that is a literal of a kind that can never serve as a raw + // value -- a regex literal, a magic identifier such as #file, or an object + // literal -- can't be used. Diagnose it before type checking (to avoid a + // spurious conversion error) and drop it, so the case receives an automatic + // value below and the enum can still conform, as it did before + // LiteralExpressions. Integer literal *expressions* are not single literals + // and are validated after folding; 'nil' flows through to the + // type-compatibility check. + if (auto *litExpr = + dyn_cast_or_null(uncheckedRawValueOf(elt))) { + if (!isValidEnumRawValueLiteral(litExpr) && + !isa(litExpr)) { + ED->getASTContext().Diags.diagnose( + litExpr->getLoc(), diag::nonliteral_enum_case_raw_value); + elt->setRawValueExpr(nullptr); + } + } + if (uncheckedRawValueOf(elt)) { if (!uncheckedRawValueOf(elt)->isImplicit()) lastExplicitValueElt = elt; @@ -1314,6 +1332,21 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { value->getLoc(), foldIntegerRawValue ? diag::nonliteral_int_expr_enum_case_raw_value : diag::nonliteral_enum_case_raw_value); + // The auto-value path above has already run, so recover here by assigning + // an automatic value directly, keeping the enum conforming. + if (!valueKind) + valueKind = computeAutomaticEnumValueKind(ED); + Expr *automatic = + valueKind ? getAutomaticRawValueExpr(*valueKind, elt, prevValue) + : nullptr; + if (automatic && + TypeChecker::typeCheckExpression( + automatic, ED, /*contextualInfo=*/{rawTy, CTP_EnumCaseRawValue})) { + elt->setRawValueExpr(automatic); + prevValue = dyn_cast(automatic); + } else { + elt->setInvalid(); + } continue; } @@ -1341,10 +1374,13 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { // Only Integer/Float/String/Bool literals can serve as raw values. Reject // any other literal -- magic identifiers such as #file/#line, regex // literals, object literals -- here, since RawValueKey below only handles - // those four kinds. + // those four kinds. Such literals are caught before type checking above, so + // this is a defensive backstop; mark the case invalid rather than feed an + // unexpected literal kind to RawValueKey. if (!isValidEnumRawValueLiteral(prevValue)) { Diags.diagnose(diagLoc, diag::nonliteral_enum_case_raw_value); prevValue = nullptr; + elt->setInvalid(); continue; } diff --git a/test/Parse/enum.swift b/test/Parse/enum.swift index 6455cf7859550..10b00c58f2d45 100644 --- a/test/Parse/enum.swift +++ b/test/Parse/enum.swift @@ -237,7 +237,7 @@ enum RawTypeWithRepeatValuesAutoInc3 : String { } enum NonliteralRawValue : Int { - case Yeon = 100 + 20 + 3 // expected-error {{raw value for enum case must be a literal}} + case Yeon = 100 + 20 + 3 } enum RawTypeWithPayload : Int { // expected-error {{'RawTypeWithPayload' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}} expected-note {{declared raw type 'Int' here}} expected-note {{declared raw type 'Int' here}} expected-note {{add stubs for conformance}} @@ -272,7 +272,7 @@ enum DuplicateMembers4 : Int { // expected-error {{'DuplicateMembers4' declares enum DuplicateMembers5 : Int { // expected-error {{'DuplicateMembers5' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}} expected-note {{add stubs for conformance}} case Foo = 1 // expected-note {{'Foo' previously declared here}} - case Foo = 1 + 1 // expected-error {{invalid redeclaration of 'Foo'}} expected-error {{raw value for enum case must be a literal}} + case Foo = 1 + 1 // expected-error {{invalid redeclaration of 'Foo'}} } enum DuplicateMembers6 { diff --git a/test/Sema/enum_raw_representable_object_literals.swift b/test/Sema/enum_raw_representable_object_literals.swift index 88fd2c14bd878..f70bbcea068ce 100644 --- a/test/Sema/enum_raw_representable_object_literals.swift +++ b/test/Sema/enum_raw_representable_object_literals.swift @@ -13,7 +13,7 @@ enum Foo: FooLiteral { // expected-error {{raw type 'FooLiteral' is not expressi typealias RawValue = Never var rawValue: Never { fatalError() } init(rawValue: Never) { fatalError() } - case bar1 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1) // expected-error {{raw value for enum case must be a literal}} - case bar2 = #imageLiteral(resourceName: "hello.png") // expected-error {{raw value for enum case must be a literal}} - case bar3 = #fileLiteral(resourceName: "what.txt") // expected-error {{raw value for enum case must be a literal}} + case bar1 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1) + case bar2 = #imageLiteral(resourceName: "hello.png") + case bar3 = #fileLiteral(resourceName: "what.txt") } diff --git a/test/decl/enum/enumtest.swift b/test/decl/enum/enumtest.swift index 9cd20c410568a..0b7bbc05ef0cb 100644 --- a/test/decl/enum/enumtest.swift +++ b/test/decl/enum/enumtest.swift @@ -302,7 +302,7 @@ func testSimpleEnum() { // https://github.com/apple/swift/issues/43127 enum E_43127: String { case Thing = "thing" - case Bob = {"test"} // expected-error {{raw value for enum case must be a literal}} + case Bob = {"test"} // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} expected-error {{raw value for enum case must be a literal}} } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 9ac76f0886857..d48a892090c1d 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -34,7 +34,7 @@ func test5(_ f : () async throws -> T) rethrows->T { // expected-note{{add ' } enum SomeEnum: Int { - case foo = await 5 // expected-error{{raw value for enum case must be a literal}} + case foo = await 5 // expected-error{{'await' operation cannot occur in an enum case raw value}} expected-error{{not supported in a literal expression}} expected-error{{raw value for enum case must be an integer literal expression}} } struct SomeStruct { From 8d48c6dca33096e7721de093a77b25fddf259bb7 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 17 Jul 2026 13:43:32 +0100 Subject: [PATCH 06/10] [Parse][Literal Expressions] Parse tuple-type generic arguments as types A parenthesized generic argument with a top-level comma is a tuple type, never a generic value argument, so route it to the type parser instead of the value-expression path. Fixes a spurious 'circular reference' when the tuple references Self or associated types in a requirement, e.g. 'associatedtype B: G<(A, Self)>'. --- lib/Parse/ParseType.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index f964a31af4e7b..5f69ac25e1395 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1622,8 +1622,9 @@ ParserResult Parser::parseTypeOrValue(Diag<> MessageID, } // A parenthesized expression that contains type-only syntax such as an opaque - // 'some' type must be parsed as a type, not a value expression: opaque types - // have to appear as TypeReprs in the enclosing declaration. + // 'some' type, or a top-level comma (making it a tuple type), must be parsed + // as a type, not a value expression: such types have to appear as TypeReprs + // in the enclosing declaration, and a tuple is never a generic value argument. if (shouldParseValueExpr && Tok.is(tok::l_paren) && parenGenericArgumentContainsTypeOnlySyntax()) shouldParseValueExpr = false; @@ -1656,6 +1657,10 @@ bool Parser::parenGenericArgumentContainsTypeOnlySyntax() { if (canParseType()) return true; } + // A top-level comma makes this a tuple type; tuples are never valid generic + // value arguments, so parse it as a type. + if (depth == 1 && Tok.is(tok::comma)) + return true; if (Tok.isAny(tok::l_paren, tok::l_square, tok::l_brace)) ++depth; else if (Tok.isAny(tok::r_paren, tok::r_square, tok::r_brace)) From 171e5ae75795bea2bf1835a076160f60b7756f5b Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 23 Jul 2026 14:02:31 +0100 Subject: [PATCH 07/10] [Literal Expressions] Separate codegen constant-folding from literal-expression verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling LiteralExpressions by default made the integer constant-folder run during code generation for every @const/@section stdlib-integer initializer (PatternBindingDecl::getExecutableInit), where it emits diagnostics. For values that are valid under CompileTimeValues but not literal expressions (e.g. MemoryLayout.size + 4, Int(17.0 / 3.5)), thatу produced a spurious "not supported in a literal expression" error, which also sets ASTContext::hadError() and so it suppressed the real "'@const' value should be initialized with a compile-time value" diagnostic emitted by the const-value SIL passes. Give ConstantFoldExpression an `emitDiagnostics` flag (part of the cache key). Verification: diagnoseInvalidConstExpressions, enum raw values, and generic value arguments, all keep folding with diagnostics. getExecutableInit folds silently and leaves diagnostics to the verifier. The recursive decl-ref fold inherits the flag so a silent fold doesn't leak sub-expression diagnostics. Also stop foldIntegerLiteralExpr from silently truncating an over-wide literal, so the existing integer-overflow diagnostic still fires. Integer arithmetic now folds in @section initializers per SE-0531, so migrate the stale operator-rejection expectations in tests. --- include/swift/AST/TypeCheckRequests.h | 12 +++- include/swift/AST/TypeCheckerTypeIDZone.def | 2 +- lib/AST/Decl.cpp | 10 ++- lib/Sema/LiteralExpressionFolding.cpp | 72 ++++++++++++++------- test/ConstValues/SectionSyntactic.swift | 20 +++--- 5 files changed, 77 insertions(+), 39 deletions(-) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 06dd7e18ca68e..a13f2cf67da62 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -5122,10 +5122,15 @@ evaluate(Evaluator &evaluator, SourceFile *SF) const; bool isCached() const { return true; } }; -/// A request to constant-fold an expression node +/// A request to constant-fold an expression node. +/// +/// \c emitDiagnostics distinguishes verification (emit diagnostics when the +/// expression cannot be folded to a literal) from code generation (fold +/// silently; a caller that also verifies owns the diagnostics). It is part of +/// the cache key so the two modes don't collide. class ConstantFoldExpression : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -5134,7 +5139,8 @@ using SimpleRequest::SimpleRequest; friend SimpleRequest; Expr * -evaluate(Evaluator &evaluator, const Expr *expr, ASTContext *ctx) const; +evaluate(Evaluator &evaluator, const Expr *expr, ASTContext *ctx, + bool emitDiagnostics) const; public: bool isCached() const { return true; } diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 1c6703bca3d1f..da05728eac541 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -698,5 +698,5 @@ SWIFT_REQUEST(TypeChecker, DesugarForEachStmtRequest, SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ConstantFoldExpression, - Expr *(const Expr *, ASTContext *), + Expr *(const Expr *, ASTContext *, bool), Cached, NoLocationInfo) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 88a173fd39e7b..9387a3217df76 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2967,8 +2967,14 @@ bool PatternBindingDecl::hasSingleVarConstantFoldedInit() const { Expr *PatternBindingDecl::getExecutableInit(unsigned i) const { auto idxInit = getPatternList()[i].getExecutableInit(); if (auto &ctx = getASTContext(); idxInit && hasSingleVarConstantFoldedInit()) - return evaluateOrDefault(ctx.evaluator, - ConstantFoldExpression{idxInit, &ctx}, {}); + // Code generation: fold silently. Any diagnostics about a non-foldable + // '@const'/'@section' initializer are the verifier's responsibility + // (diagnoseInvalidConstExpressions), not code generation's -- emitting them + // here would duplicate/preempt those and set the error flag that makes the + // const-value SIL passes bail. + return evaluateOrDefault( + ctx.evaluator, + ConstantFoldExpression{idxInit, &ctx, /*emitDiagnostics=*/false}, {}); return idxInit; } diff --git a/lib/Sema/LiteralExpressionFolding.cpp b/lib/Sema/LiteralExpressionFolding.cpp index a2a25c0ad0351..32aecdb46b9ae 100644 --- a/lib/Sema/LiteralExpressionFolding.cpp +++ b/lib/Sema/LiteralExpressionFolding.cpp @@ -200,9 +200,14 @@ class IntegerValue : public ConstantValue { /// value operands. class ConstantFolder { ASTContext &Ctx; + /// Whether to emit diagnostics when the expression cannot be folded to a + /// literal. Verification passes this true; code generation passes it false + /// and leaves diagnostics to the verifier. + bool EmitDiagnostics; public: - ConstantFolder(ASTContext &ctx) : Ctx(ctx) {} + ConstantFolder(ASTContext &ctx, bool emitDiagnostics) + : Ctx(ctx), EmitDiagnostics(emitDiagnostics) {} Expr *fold(const Expr *expr) { // If this expression failed to type-check, no need to attempt to // fold it since we likely won't be able to do anything meaningful @@ -213,7 +218,7 @@ class ConstantFolder { return nullptr; } - ConstantWalker walker(Ctx); + ConstantWalker walker(Ctx, EmitDiagnostics); const_cast(expr)->walk(walker); ASSERT(walker.hasConstantValueFor(expr) && "No value or error computed by constant-folding AST walker"); @@ -229,11 +234,13 @@ class ConstantFolder { private: class ConstantWalker : public ASTWalker { ASTContext &Ctx; + bool EmitDiagnostics; llvm::DenseMap> ConstValuesOrErrors; public: - ConstantWalker(ASTContext &ctx) : Ctx(ctx) {} + ConstantWalker(ASTContext &ctx, bool emitDiagnostics) + : Ctx(ctx), EmitDiagnostics(emitDiagnostics) {} PostWalkResult walkToExprPost(Expr *expr) override { ConstValuesOrErrors.insert({expr, tryFoldExpression(expr)}); @@ -277,15 +284,25 @@ class ConstantFolder { return FoldingError(IllegalConstError::Default, expr->getLoc()); } - ConstantValuePtr foldIntegerLiteralExpr(const IntegerLiteralExpr *expr) { + FoldingErrorOr + foldIntegerLiteralExpr(const IntegerLiteralExpr *expr) { auto exprType = expr->getType(); auto value = expr->getValue(); auto resultBitWidth = getIntegerBitWidth(exprType, Ctx); - if (isSignedIntegerType(exprType)) - return std::make_unique(value.sextOrTrunc(resultBitWidth), - true); - return std::make_unique(value.zextOrTrunc(resultBitWidth), - false); + bool isSigned = isSignedIntegerType(exprType); + // Don't silently truncate a literal whose magnitude doesn't fit the + // target type; leave it unfolded so the existing overflow diagnostic + // (from the SIL constant-propagation pass, or the type checker) still + // fires. UpstreamError suppresses the generic folding follow-up. + unsigned needed = + isSigned ? value.getSignificantBits() : value.getActiveBits(); + if (needed > resultBitWidth) + return FoldingError(IllegalConstError::UpstreamError, expr->getLoc()); + if (isSigned) + return ConstantValuePtr(std::make_unique( + value.sextOrTrunc(resultBitWidth), true)); + return ConstantValuePtr(std::make_unique( + value.zextOrTrunc(resultBitWidth), false)); } FoldingErrorOr tryFoldBinaryExpr(const BinaryExpr *expr) { @@ -355,7 +372,6 @@ class ConstantFolder { FoldingErrorOr foldDeclRefExpr(const DeclRefExpr *expr) { if (const VarDecl *varDecl = dyn_cast(expr->getDecl())) return foldVarDeclRef(varDecl, expr->getLoc()); - return FoldingError(IllegalConstError::OpaqueDeclRef, expr->getLoc()); } @@ -386,15 +402,17 @@ class ConstantFolder { if (!varDecl->hasClangNode() && varDecl->isLet()) { auto access = varDecl->getFormalAccess(); if (access >= AccessLevel::Package) { - Ctx.Diags.diagnose(referenceLoc, diag::const_public_let_ref, access); + if (EmitDiagnostics) + Ctx.Diags.diagnose(referenceLoc, diag::const_public_let_ref, access); return FoldingError(IllegalConstError::UpstreamError, referenceLoc); } // Safe here: the package/public/open cases returned above, so the // formal access is below public as `isUsableFromInline()` asserts. if (varDecl->isUsableFromInline()) { - Ctx.Diags.diagnose(referenceLoc, - diag::const_usable_from_inline_let_ref); + if (EmitDiagnostics) + Ctx.Diags.diagnose(referenceLoc, + diag::const_usable_from_inline_let_ref); return FoldingError(IllegalConstError::UpstreamError, referenceLoc); } } @@ -429,12 +447,15 @@ class ConstantFolder { FoldingErrorOr tryFoldDeclRefInitializerExpr(const Expr *expr, SourceLoc referenceLoc) { - bool previouslyFolded = - Ctx.evaluator.hasCachedResult(ConstantFoldExpression{expr, &Ctx}); + // Recurse with the same diagnostic mode as this fold, so a silent + // (code-generation) fold does not leak sub-expression diagnostics. + bool previouslyFolded = Ctx.evaluator.hasCachedResult( + ConstantFoldExpression{expr, &Ctx, EmitDiagnostics}); // Request the init expression of this declaration to be // constant-folded. - if (auto foldedLiteralExpr = - dyn_cast(swift::foldLiteralExpression(expr, &Ctx))) + if (auto foldedLiteralExpr = dyn_cast(evaluateOrDefault( + Ctx.evaluator, ConstantFoldExpression{expr, &Ctx, EmitDiagnostics}, + {}))) return tryFoldLiteralExpression(foldedLiteralExpr); // If this is the first time we have requested to constant-fold this // declaration's initializer and have failed to do so, emit a note @@ -534,14 +555,16 @@ class ConstantFolder { // amount and bit width; return `UpstreamError` to suppress the // generic "not a literal expression" follow-up. if (rhsVal->getIsSigned() && rhsInt.isNegative()) { - Ctx.Diags.diagnose(sourceLocation, diag::const_shift_negative); + if (EmitDiagnostics) + Ctx.Diags.diagnose(sourceLocation, diag::const_shift_negative); return FoldingError(IllegalConstError::UpstreamError, sourceLocation); } unsigned width = lhsInt.getBitWidth(); uint64_t amountValue = rhsInt.getLimitedValue(); if (amountValue >= width) { - Ctx.Diags.diagnose(sourceLocation, diag::const_shift_out_of_range, - static_cast(amountValue), width); + if (EmitDiagnostics) + Ctx.Diags.diagnose(sourceLocation, diag::const_shift_out_of_range, + static_cast(amountValue), width); return FoldingError(IllegalConstError::UpstreamError, sourceLocation); } unsigned amount = static_cast(amountValue); @@ -637,18 +660,23 @@ class ConstantFolder { } void emitFoldingErrorDiagnostic(const FoldingError &foldingError) { + if (!EmitDiagnostics) + return; diagnoseError(foldingError.sourceLocation, foldingError.code, Ctx.Diags); } }; } // anonymous namespace Expr *swift::foldLiteralExpression(const Expr *expr, ASTContext *ctx) { - return evaluateOrDefault(ctx->evaluator, ConstantFoldExpression{expr, ctx}, + return evaluateOrDefault(ctx->evaluator, + ConstantFoldExpression{expr, ctx, + /*emitDiagnostics=*/true}, {}); } Expr *ConstantFoldExpression::evaluate(Evaluator &evaluator, const Expr *expr, - ASTContext *ctx) const { + ASTContext *ctx, + bool emitDiagnostics) const { // Only integer literal expressions are folded. Expressions of other types // (non-integer literals, tuples, arrays, ...) are returned unchanged so they // are never routed through the integer constant-folder, which would reject diff --git a/test/ConstValues/SectionSyntactic.swift b/test/ConstValues/SectionSyntactic.swift index 173cca4812880..51477b66e6e99 100644 --- a/test/ConstValues/SectionSyntactic.swift +++ b/test/ConstValues/SectionSyntactic.swift @@ -23,22 +23,21 @@ // magic literals @section("mysection") let invalidNonLiteral4 = #line +// expected-error@-1{{not supported in a literal expression}} -// operators (should be rejected) -@section("mysection") let invalidOperator1 = 1 + 1 -// expected-error@-1{{unsupported operator in a literal expression}} +// operators (integer arithmetic folds; non-integer operators are rejected) +@section("mysection") let validOperator1 = 1 + 1 // ok (folds to 2) @section("mysection") let invalidOperator2 = 3.14 * 2.0 // expected-error@-1{{unsupported operator in a literal expression}} -@section("mysection") let invalidOperator3: Int = -(1) -// expected-error@-1{{unsupported operator in a literal expression}} +@section("mysection") let validOperator3: Int = -(1) // ok (folds to -1) // non-literal expressions (should be rejected) @section("mysection") let invalidNonLiteral1 = Int.max -// expected-error@-1{{not supported in a literal expression}} +// expected-error@-1{{unable to resolve variable reference in a literal expression}} @section("mysection") let invalidNonLiteral2 = UInt64(42) -// expected-error@-1{{unsupported type in a literal expression}} -@section("mysection") let invalidNonLiteral3 = true.hashValue // expected-error@-1{{not supported in a literal expression}} +@section("mysection") let invalidNonLiteral3 = true.hashValue +// expected-error@-1{{unable to resolve variable reference in a literal expression}} func foo() -> Int { return 42 } func bar(x: Int) -> String { return "test" } @@ -154,9 +153,8 @@ enum E { case a } let someVar = 42 -// variables (should be rejected) -@section("mysection") let invalidVarRef = someVar -// expected-error@-1{{unable to resolve variable reference in a literal expression}} +// reference to a compile-time-known integer 'let' folds +@section("mysection") let validVarRef = someVar // ok (folds to 42) struct MyCustomExpressibleByIntegerLiteral: ExpressibleByIntegerLiteral { init(integerLiteral value: Int) {} From ee75fcc3c8329387663f388942536dfda6a53318 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 17 Jul 2026 16:42:10 +0100 Subject: [PATCH 08/10] [ASTPrinter] Print explicit enum raw values that were constant-folded With LiteralExpressions enabled, getRawValueExpr() returns the constant-folded literal, which is always implicit. printEnumElement used the folded value's implicit-ness to tell an explicit raw value from an auto-incremented one, so every explicit raw value ('case a = 1', 'case a = 2 + 3') was dropped from printed output. Determine explicitness from getOriginalRawValueExpr() (the pre-folding expression, whose implicit-ness still reflects whether a raw value was written) and print the folded value. --- lib/AST/ASTPrinter.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index cbe61d54c4c80..bf10d60be9947 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4897,8 +4897,15 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) { break; } + // Whether a raw value was written explicitly is determined from the original + // (pre-folded) expression: constant folding produces an implicit literal. + // The folded value is what gets printed (e.g. '2 + 3' prints as '5'). + if (auto *original = elt->getOriginalRawValueExpr(); + !original || original->isImplicit()) + return; + auto *raw = elt->getRawValueExpr(); - if (!raw || raw->isImplicit()) + if (!raw) return; // Print the explicit raw value expression. From 6185a4e05d3fbbde2338524f6bae0012e623ca29 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 17 Jul 2026 16:42:59 +0100 Subject: [PATCH 09/10] [Sema] Don't fold a negative literal into an unsigned type `foldIntegerLiteralExpr` already leaves an over-magnitude literal unfolded so the existing integer-overflow diagnostic fires instead of wrapping it, but a negative literal in an unsigned type slipped through: 'expr->getValue()' wraps it (e.g. '-1' as 'UInt8' becomes 255), so the bit-width check didn't catch it. The wrapped value could even collide with another enum raw value ("raw value for enum case is not unique"), masking "negative integer '-1' overflows when stored into unsigned type 'UInt8'". Reject a negative literal for an unsigned type up front, before getValue() wraps it, leaving it unfolded so the overflow diagnostic still fires. --- lib/Sema/LiteralExpressionFolding.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/Sema/LiteralExpressionFolding.cpp b/lib/Sema/LiteralExpressionFolding.cpp index 32aecdb46b9ae..2963effae1f6b 100644 --- a/lib/Sema/LiteralExpressionFolding.cpp +++ b/lib/Sema/LiteralExpressionFolding.cpp @@ -287,13 +287,18 @@ class ConstantFolder { FoldingErrorOr foldIntegerLiteralExpr(const IntegerLiteralExpr *expr) { auto exprType = expr->getType(); - auto value = expr->getValue(); auto resultBitWidth = getIntegerBitWidth(exprType, Ctx); bool isSigned = isSignedIntegerType(exprType); - // Don't silently truncate a literal whose magnitude doesn't fit the - // target type; leave it unfolded so the existing overflow diagnostic - // (from the SIL constant-propagation pass, or the type checker) still - // fires. UpstreamError suppresses the generic folding follow-up. + // A literal whose value doesn't fit the target type is left unfolded so + // the existing overflow diagnostic (from the SIL constant-propagation + // pass, or the type checker) still fires, rather than folding it to a + // wrapped value. UpstreamError suppresses the generic folding follow-up. + // A negative literal never fits an unsigned type; other overflows are + // caught by the significant/active bit width. 'expr->getValue()' would + // already wrap a negative value, so test negativity first. + if (!isSigned && expr->isNegative()) + return FoldingError(IllegalConstError::UpstreamError, expr->getLoc()); + auto value = expr->getValue(); unsigned needed = isSigned ? value.getSignificantBits() : value.getActiveBits(); if (needed > resultBitWidth) From 315a9414500c99e993ebda7847589f11cdb2b386 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 14 Jul 2026 17:12:45 +0100 Subject: [PATCH 10/10] [Literal Expressions] Enable by-default The Literal Expressions feature has been accepted into the language --- include/swift/AST/Decl.h | 5 ++--- include/swift/AST/DiagnosticsSema.def | 2 -- include/swift/Basic/Features.def | 2 +- lib/AST/ASTDumper.cpp | 20 ++++++----------- lib/AST/Decl.cpp | 16 +++++--------- lib/ASTGen/Sources/ASTGen/SourceFile.swift | 1 - lib/Parse/ParseDecl.cpp | 22 ------------------- lib/Parse/ParseType.cpp | 8 +++---- lib/Sema/LegalLiteralExprVerifier.cpp | 3 +-- lib/Sema/LiteralExpressionFolding.cpp | 5 ++--- lib/Sema/TypeCheckDecl.cpp | 9 ++------ lib/Sema/TypeCheckType.cpp | 9 -------- .../LiteralExpressions/ArithmeticErrors.swift | 3 +-- test/LiteralExpressions/EnumRawValue.swift | 3 +-- .../LiteralExpressions/EnumRawValueFail.swift | 3 +-- .../EnumRawValueInterface.swift | 3 +-- test/LiteralExpressions/EnumRawValueRun.swift | 3 +-- .../IntegerGenericArithmetic.swift | 3 +-- .../IntegerGenericConstantFolding.swift | 3 +-- .../IntegerGenericErrors.swift | 3 +-- .../IntegerGenericExpressionInterface.swift | 3 +-- ...erGenericExpressionRequirementErrors.swift | 3 +-- test/LiteralExpressions/LargeInt.swift | 3 +-- test/LiteralExpressions/LiteralOperands.swift | 3 +-- .../NonIntegerRawValues.swift | 3 +-- .../LiteralExpressions/SectionInterface.swift | 3 +-- .../VariableReferenceFail.swift | 3 +-- .../VariableReferences.swift | 3 +-- .../VisibilityRestriction.swift | 4 +--- 29 files changed, 41 insertions(+), 113 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 1bd5138500893..0b4f3a910d71b 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -9151,9 +9151,8 @@ class EnumElementDecl : public DeclContext, public ValueDecl { /// exists, as it was written in the source. Expr *getOriginalRawValueExpr() const; - /// Retrieves a fully-typechecked and (if LiteralExpressions experimental - /// feature is enabled) constant-folded raw value expression associated with - /// this enum element, if it exists. + /// Retrieves a fully-typechecked and constant-folded raw value expression + /// associated with this enum element, if it exists. LiteralExpr *getRawValueExpr() const; /// Reset the raw value expression. diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7ed6e326f81ab..ba93e4c963f83 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -9033,8 +9033,6 @@ ERROR(availability_value_generic_type_only_version_newer, none, ERROR(invalid_value_for_type_same_type,none, "cannot constrain type parameter %0 to be integer %1", (Type, Type)) -ERROR(nonliteral_integer_generic_value,none, - "generic value must be an integer literal", ()) ERROR(nonliteral_integer_expr_generic_value,none, "generic value must be an integer literal expression", ()) ERROR(integer_generic_expr_closure_not_supported,none, diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 57d599c7f89e7..e6a63f39f3b11 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -561,7 +561,7 @@ EXPERIMENTAL_FEATURE(CompileTimeValues, true) EXPERIMENTAL_FEATURE(CompileTimeValuesPreview, false) /// Allow use of literal expressions as literals -EXPERIMENTAL_FEATURE(LiteralExpressions, true) +LANGUAGE_FEATURE(LiteralExpressions, 531, "literal expressions") /// Allow function body macros applied to closures. EXPERIMENTAL_FEATURE(ClosureBodyMacro, true) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index bc023c6e45697..ce89f5b71becd 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2765,19 +2765,13 @@ namespace { // triggering EnumRawValuesRequest which requres type-checking. if (isTypeChecked()) { if (auto *rawValueExpr = EED->getRawValueExpr()) { - if (EED->getASTContext().LangOpts.hasFeature( - Feature::LiteralExpressions)) { - auto origRawValueExpr = EED->getOriginalRawValueExpr(); - if (isa(origRawValueExpr)) - printRec(origRawValueExpr, Label::always("raw_value_expr")); - else { - printRec(EED->getOriginalRawValueExpr(), - Label::always("original_raw_value_expr")); - printRec(EED->getRawValueExpr(), - Label::always("folded_raw_value_expr")); - } - } else { - printRec(rawValueExpr, Label::always("raw_value_expr")); + auto origRawValueExpr = EED->getOriginalRawValueExpr(); + if (isa(origRawValueExpr)) + printRec(origRawValueExpr, Label::always("raw_value_expr")); + else { + printRec(origRawValueExpr, + Label::always("original_raw_value_expr")); + printRec(rawValueExpr, Label::always("folded_raw_value_expr")); } } } else if (auto *rawValueExpr = EED->getRawValueUnchecked()) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9387a3217df76..4857a877e8ecc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2954,8 +2954,7 @@ VarDecl *PatternBindingDecl::getAnchoringVarDecl(unsigned i) const { bool PatternBindingDecl::hasSingleVarConstantFoldedInit() const { auto *singleVar = getSingleVar(); - if (!singleVar || !singleVar->isConstValue() || - !getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions)) + if (!singleVar || !singleVar->isConstValue()) return false; // Only stdlib integer constants participate in literal-expression folding. // Other constant initializers (tuples, arrays, strings, ...) are left as @@ -12271,14 +12270,11 @@ LiteralExpr *EnumElementDecl::getRawValueExpr() const { // 'EnumRawValuesRequest' so this is meant to return the // cached result, if the above request was successful. if (RawValueExpr) - if (getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions)) - return dyn_cast(evaluateOrDefault( - getASTContext().evaluator, - ConstantFoldExpression{RawValueExpr, &getASTContext()}, {})); - else - return dyn_cast(RawValueExpr); - else - return nullptr; + return dyn_cast(evaluateOrDefault( + getASTContext().evaluator, ConstantFoldExpression{ + RawValueExpr, &getASTContext(), + /*emitDiagnostics*/ true}, {})); + return nullptr; } void EnumElementDecl::setRawValueExpr(Expr *e) { diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index 94d262a8a0ac0..03433dd5ef392 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -93,7 +93,6 @@ extension Parser.ExperimentalFeatures { mapFeature(.KeyPathWithMethodMembers, to: .keypathWithMethodMembers) mapFeature(.DefaultIsolationPerFile, to: .defaultIsolationPerFile) mapFeature(.BorrowAndMutateAccessors, to: .borrowAndMutateAccessors) - mapFeature(.LiteralExpressions, to: .literalExpressions) } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index aafbdb5609ca0..0695fc9fc0281 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -9715,20 +9715,6 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, return DCC.fixupParserResult(Status, ED); } -static bool isValidEnumRawValueLiteral(Expr *expr) { - if (expr == nullptr) - return false; - - if (!isa(expr) && - !isa(expr) && - !isa(expr) && - !isa(expr) && - !isa(expr)) - return false; - - return true; -} - /// Parse a 'case' of an enum. /// /// \verbatim @@ -9843,14 +9829,6 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags, Status.setIsParseError(); return Status; } - - if (!Context.LangOpts.hasFeature(Feature::LiteralExpressions)) { - if (!isValidEnumRawValueLiteral(RawValueExpr.getPtrOrNull())) { - diagnose(RawValueExpr.getPtrOrNull()->getLoc(), - diag::nonliteral_enum_case_raw_value); - RawValueExpr = nullptr; - } - } } // For recovery, again make sure the user didn't try to spell a switch diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 5f69ac25e1395..99b0ee181139b 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1612,8 +1612,7 @@ ParserResult Parser::parseTypeOrValue(Diag<> MessageID, // Look ahead to consider if this is a generic value expression // or possibly a tuple type with a postfix grammar bool shouldParseValueExpr = false; - if (Context.LangOpts.hasFeature(Feature::LiteralExpressions) && - Tok.is(tok::l_paren)) { + if (Tok.is(tok::l_paren)) { BacktrackingScope backtrack(*this); skipSingle(); if (Tok.is(tok::comma) || startsWithGreater(Tok) || @@ -1764,7 +1763,7 @@ bool Parser::canParseGenericArguments() { return true; } - do { + do { // A generic argument may be a parenthesized value expression such as // '(1 + 2)'. Treat a parenthesized group as a value expression only when // it is immediately followed by ',' or '>'; otherwise parse it as a type @@ -2002,8 +2001,7 @@ bool Parser::canParseStartOfInlineArrayType() { // expression or type. We specifically look for any type, not just integers // for better recovery in e.g cases where the user writes '[Int of 2]'. We // only do type-scalar since variadics would be ambiguous e.g 'Int...of'. - if (Context.LangOpts.hasFeature(Feature::LiteralExpressions) && - Tok.is(tok::l_paren)) + if (Tok.is(tok::l_paren)) skipSingle(); // Assume a parentheses-delimited value expression else if (!canParseTypeScalar()) return false; diff --git a/lib/Sema/LegalLiteralExprVerifier.cpp b/lib/Sema/LegalLiteralExprVerifier.cpp index 4e5e594288459..047f6c5cad046 100644 --- a/lib/Sema/LegalLiteralExprVerifier.cpp +++ b/lib/Sema/LegalLiteralExprVerifier.cpp @@ -589,8 +589,7 @@ void swift::diagnoseInvalidConstExpressions(const Expr *expr, if (auto error = checkSupportedInConst(expr, declContext)) diagnoseError(error->first->getLoc(), error->second, ctx.Diags); } else { - if (ctx.LangOpts.hasFeature(Feature::LiteralExpressions) && - expr->getType()->isStdlibInteger()) + if (expr->getType()->isStdlibInteger()) foldLiteralExpression(expr, &ctx); else if (auto error = checkSupportedWithSectionAttribute(expr, declContext)) diff --git a/lib/Sema/LiteralExpressionFolding.cpp b/lib/Sema/LiteralExpressionFolding.cpp index 2963effae1f6b..792af8a646751 100644 --- a/lib/Sema/LiteralExpressionFolding.cpp +++ b/lib/Sema/LiteralExpressionFolding.cpp @@ -686,9 +686,8 @@ Expr *ConstantFoldExpression::evaluate(Evaluator &evaluator, const Expr *expr, // (non-integer literals, tuples, arrays, ...) are returned unchanged so they // are never routed through the integer constant-folder, which would reject // them with a spurious diagnostic. - if (ctx->LangOpts.hasFeature(Feature::LiteralExpressions) && - expr->getType() && expr->getType()->isStdlibInteger()) { - ConstantFolder folder(*ctx); + if (expr->getType() && expr->getType()->isStdlibInteger()) { + ConstantFolder folder(*ctx, emitDiagnostics); if (auto result = folder.fold(expr)) return result; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 3859871626ca1..bf8d2e5271187 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1313,10 +1313,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { // types (String, Float, ...) use the written literal directly. Gating on // an integer raw type keeps non-integer initializers from being routed // through the integer constant-folder, which would reject them. - bool literalExprEnabled = - ED->getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions); - bool foldIntegerRawValue = - literalExprEnabled && rawTy && rawTy->isStdlibInteger(); + bool foldIntegerRawValue = rawTy && rawTy->isStdlibInteger(); // We must reduce the expression to a LiteralExpr here so that: // 1. We validate the expression *is* a usable raw value. // 2. We can use it to compute the next automatic raw value expression. @@ -1325,9 +1322,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED) const { foldLiteralExpression(value, &ED->getASTContext())) : dyn_cast(value); if (!prevValue) { - // When the feature is disabled, non-literal raw values are already - // rejected during parsing; only diagnose here when it is enabled. - if (literalExprEnabled && value) + if (value) ED->getASTContext().Diags.diagnose( value->getLoc(), foldIntegerRawValue ? diag::nonliteral_int_expr_enum_case_raw_value diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 2c6c30a33cc14..fb1f60baec48a 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -5987,15 +5987,6 @@ NeverNullType TypeResolver::resolveGenericArgumentExprTypeRepr( getASTContext()); }; - // We expect there to only be an 'IntegerLiteralExpr' when the LiteralExpressions - // feature is not enabled. - if (!getASTContext().LangOpts.hasFeature(Feature::LiteralExpressions)) { - if (auto litExpr = dyn_cast(originalValueExpr)) - return resolveIntegerLiteralExpr(litExpr); - else - return failedToResolveValue(diag::nonliteral_integer_generic_value); - } - // We have already attempted to resolve this TypeRepr if (repr->failedToResolve()) return ErrorType::get(getASTContext()); diff --git a/test/LiteralExpressions/ArithmeticErrors.swift b/test/LiteralExpressions/ArithmeticErrors.swift index b75d862e919a5..cd1e69c6fc167 100644 --- a/test/LiteralExpressions/ArithmeticErrors.swift +++ b/test/LiteralExpressions/ArithmeticErrors.swift @@ -1,6 +1,5 @@ // Constant globals using @section initialized with literal expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature LiteralExpressions -verify +// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify @section("mysection") let overflow: UInt8 = 100 * 3 // expected-error {{operation results in integer overflow}} @section("mysection") let divideZero1 = 4 / 0 // expected-error {{division by zero}} diff --git a/test/LiteralExpressions/EnumRawValue.swift b/test/LiteralExpressions/EnumRawValue.swift index 0fd065bfa491f..b3c6719d2837f 100644 --- a/test/LiteralExpressions/EnumRawValue.swift +++ b/test/LiteralExpressions/EnumRawValue.swift @@ -1,6 +1,5 @@ // Enum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -typecheck -dump-ast %s -enable-experimental-feature LiteralExpressions -verify | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -dump-ast %s -verify | %FileCheck %s enum E1: Int { case a = 2 + 2 diff --git a/test/LiteralExpressions/EnumRawValueFail.swift b/test/LiteralExpressions/EnumRawValueFail.swift index a9d8f83d971bf..45101d17acd9a 100644 --- a/test/LiteralExpressions/EnumRawValueFail.swift +++ b/test/LiteralExpressions/EnumRawValueFail.swift @@ -1,6 +1,5 @@ // Enum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -typecheck %s -enable-experimental-feature LiteralExpressions -verify -verify-ignore-unrelated +// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unrelated enum E1: Int { case a = 2 + Int.random(in: 0 ..< 10) diff --git a/test/LiteralExpressions/EnumRawValueInterface.swift b/test/LiteralExpressions/EnumRawValueInterface.swift index d44b524a96d8d..3f1e342997736 100644 --- a/test/LiteralExpressions/EnumRawValueInterface.swift +++ b/test/LiteralExpressions/EnumRawValueInterface.swift @@ -1,6 +1,5 @@ // Enum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -emit-module -module-name EnumRawValueInterface -emit-module-interface-path %t/EnumRawValueInterface.swiftinterface -enable-library-evolution -swift-version 5 %s -enable-experimental-feature LiteralExpressions +// RUN: %target-swift-frontend -emit-module -module-name EnumRawValueInterface -emit-module-interface-path %t/EnumRawValueInterface.swiftinterface -enable-library-evolution -swift-version 5 %s // RUN: %FileCheck %s < %t/EnumRawValueInterface.swiftinterface // CHECK-LABEL: public enum E1 : Swift::Int { diff --git a/test/LiteralExpressions/EnumRawValueRun.swift b/test/LiteralExpressions/EnumRawValueRun.swift index 2e73424606bb6..bfa09f6c0543e 100644 --- a/test/LiteralExpressions/EnumRawValueRun.swift +++ b/test/LiteralExpressions/EnumRawValueRun.swift @@ -1,7 +1,6 @@ // Enum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions // REQUIRES: executable_test -// RUN: %target-run-simple-swift(-enable-experimental-feature LiteralExpressions) | %FileCheck %s --dump-input=always +// RUN: %target-run-simple-swift | %FileCheck %s --dump-input=always // CHECK: 1 // CHECK-NEXT: 2 diff --git a/test/LiteralExpressions/IntegerGenericArithmetic.swift b/test/LiteralExpressions/IntegerGenericArithmetic.swift index f87ba282f2064..2fbc7df0a1518 100644 --- a/test/LiteralExpressions/IntegerGenericArithmetic.swift +++ b/test/LiteralExpressions/IntegerGenericArithmetic.swift @@ -1,6 +1,5 @@ // Literal expressions in integer generic parameter values -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature LiteralExpressions -verify +// RUN: %target-typecheck-verify-swift -disable-availability-checking -verify // ============================================================================= // Arithmetic operators diff --git a/test/LiteralExpressions/IntegerGenericConstantFolding.swift b/test/LiteralExpressions/IntegerGenericConstantFolding.swift index 1942bd9e2450a..51094539580d4 100644 --- a/test/LiteralExpressions/IntegerGenericConstantFolding.swift +++ b/test/LiteralExpressions/IntegerGenericConstantFolding.swift @@ -1,6 +1,5 @@ // Complex literal expressions in integer generic parameter values with AST verification -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -typecheck -dump-ast %s -disable-availability-checking -enable-experimental-feature LiteralExpressions | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -dump-ast %s -disable-availability-checking | %FileCheck %s let foldAdd: InlineArray<(2 + 3), Int> = [1, 2, 3, 4, 5] // CHECK-LABEL: (pattern_named type="InlineArray<5, Int>" "foldAdd") diff --git a/test/LiteralExpressions/IntegerGenericErrors.swift b/test/LiteralExpressions/IntegerGenericErrors.swift index c9ef3e8956852..7834a451b1403 100644 --- a/test/LiteralExpressions/IntegerGenericErrors.swift +++ b/test/LiteralExpressions/IntegerGenericErrors.swift @@ -1,6 +1,5 @@ // Error cases for literal expressions in integer generic parameter values -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature LiteralExpressions +// RUN: %target-typecheck-verify-swift -disable-availability-checking let wrongCount1: InlineArray<(2 + 3), Int> = [1, 2, 3] // expected-error@-1 {{expected 5 elements in inline array literal, but got 3}} diff --git a/test/LiteralExpressions/IntegerGenericExpressionInterface.swift b/test/LiteralExpressions/IntegerGenericExpressionInterface.swift index 452d05b7096da..08e01622f9b77 100644 --- a/test/LiteralExpressions/IntegerGenericExpressionInterface.swift +++ b/test/LiteralExpressions/IntegerGenericExpressionInterface.swift @@ -1,6 +1,5 @@ // Integer generic expression interface printingEnum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -emit-module -module-name IntegerGenericExpressionInterface -emit-module-interface-path %t/IntegerGenericExpressionInterface.swiftinterface -enable-library-evolution -swift-version 5 -disable-availability-checking %s -enable-experimental-feature LiteralExpressions +// RUN: %target-swift-frontend -emit-module -module-name IntegerGenericExpressionInterface -emit-module-interface-path %t/IntegerGenericExpressionInterface.swiftinterface -enable-library-evolution -swift-version 5 -disable-availability-checking %s // RUN: %FileCheck %s < %t/IntegerGenericExpressionInterface.swiftinterface diff --git a/test/LiteralExpressions/IntegerGenericExpressionRequirementErrors.swift b/test/LiteralExpressions/IntegerGenericExpressionRequirementErrors.swift index 026beffe89247..4327a2f0d3a90 100644 --- a/test/LiteralExpressions/IntegerGenericExpressionRequirementErrors.swift +++ b/test/LiteralExpressions/IntegerGenericExpressionRequirementErrors.swift @@ -1,6 +1,5 @@ // Error cases for literal expressions in integer generic parameter values -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature LiteralExpressions +// RUN: %target-typecheck-verify-swift -disable-availability-checking struct V {} // expected-note@-1 {{arguments to generic parameter 'N' ('2' and '5') are expected to be equal}} diff --git a/test/LiteralExpressions/LargeInt.swift b/test/LiteralExpressions/LargeInt.swift index db46e5dc875ad..33cb495454315 100644 --- a/test/LiteralExpressions/LargeInt.swift +++ b/test/LiteralExpressions/LargeInt.swift @@ -1,7 +1,6 @@ // Constant globals using @section initialized with literal expressions -// REQUIRES: swift_feature_LiteralExpressions // REQUIRES: OS=macosx -// RUN: %target-swift-frontend -typecheck -dump-ast %s -enable-experimental-feature LiteralExpressions -target %target-cpu-apple-macosx15.0 -verify | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -dump-ast %s -target %target-cpu-apple-macosx15.0 -verify | %FileCheck %s @section("mysection") let largeInt: Int128 = 128 + 2 // CHECK-LABEL: (pattern_named type="Int128" "largeInt") diff --git a/test/LiteralExpressions/LiteralOperands.swift b/test/LiteralExpressions/LiteralOperands.swift index 0b27e03f0a2a3..a3725e0671c3e 100644 --- a/test/LiteralExpressions/LiteralOperands.swift +++ b/test/LiteralExpressions/LiteralOperands.swift @@ -1,6 +1,5 @@ // Constant globals using @section initialized with literal expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -typecheck -dump-ast %s -enable-experimental-feature LiteralExpressions -verify | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -dump-ast %s -verify | %FileCheck %s // Simple arithmetic operators on integers @section("mysection") let intBinaryArithOp1 = 1 + 1 diff --git a/test/LiteralExpressions/NonIntegerRawValues.swift b/test/LiteralExpressions/NonIntegerRawValues.swift index 1bd76c561157d..a408e64b5d40d 100644 --- a/test/LiteralExpressions/NonIntegerRawValues.swift +++ b/test/LiteralExpressions/NonIntegerRawValues.swift @@ -5,8 +5,7 @@ // diagnostic), and non-literal / magic-identifier raw values must be rejected // rather than tripping an assertion in RawValueKey. -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unrelated -enable-experimental-feature LiteralExpressions +// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unrelated // Non-integer raw values are accepted as written (not folded). enum StringEnum: String { case a = "foo"; case b = "bar" } diff --git a/test/LiteralExpressions/SectionInterface.swift b/test/LiteralExpressions/SectionInterface.swift index 8aad0c8fd3a32..0159fa9831bfe 100644 --- a/test/LiteralExpressions/SectionInterface.swift +++ b/test/LiteralExpressions/SectionInterface.swift @@ -1,6 +1,5 @@ // Enum case raw value expressions -// REQUIRES: swift_feature_LiteralExpressions -// RUN: %target-swift-frontend -emit-module -module-name SectionLiteralExprInterface -emit-module-interface-path %t/SectionLiteralExprInterface.swiftinterface -enable-library-evolution -swift-version 5 %s -enable-experimental-feature LiteralExpressions +// RUN: %target-swift-frontend -emit-module -module-name SectionLiteralExprInterface -emit-module-interface-path %t/SectionLiteralExprInterface.swiftinterface -enable-library-evolution -swift-version 5 %s // RUN: %FileCheck %s < %t/SectionLiteralExprInterface.swiftinterface // Simple arithmetic operators on integers diff --git a/test/LiteralExpressions/VariableReferenceFail.swift b/test/LiteralExpressions/VariableReferenceFail.swift index bee70bcb3a80d..1beebdab0b132 100644 --- a/test/LiteralExpressions/VariableReferenceFail.swift +++ b/test/LiteralExpressions/VariableReferenceFail.swift @@ -1,8 +1,7 @@ // Constant globals using @section initialized with literal expressions with simple variable references -// REQUIRES: swift_feature_LiteralExpressions // RUN: %empty-directory(%t/deps) -// RUN: %target-swift-frontend -typecheck %s -enable-experimental-feature LiteralExpressions -verify +// RUN: %target-swift-frontend -typecheck %s -verify // This declaration is not itself declared to be a constant value // but is referenced from one. Upon emitting a failure to constant fold, ensure diff --git a/test/LiteralExpressions/VariableReferences.swift b/test/LiteralExpressions/VariableReferences.swift index 482ef7690d7d7..df3530b08c648 100644 --- a/test/LiteralExpressions/VariableReferences.swift +++ b/test/LiteralExpressions/VariableReferences.swift @@ -1,9 +1,8 @@ // Constant globals using @section initialized with literal expressions with simple variable references -// REQUIRES: swift_feature_LiteralExpressions // RUN: %empty-directory(%t/deps) // RUN: split-file %s %t -// RUN: %target-swift-frontend -typecheck -dump-ast %t/client.swift -I %t/deps -enable-experimental-feature LiteralExpressions -verify | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -dump-ast %t/client.swift -I %t/deps -verify | %FileCheck %s //--- deps/foo.h #define MACRO_INT 42 diff --git a/test/LiteralExpressions/VisibilityRestriction.swift b/test/LiteralExpressions/VisibilityRestriction.swift index 43671eb94db23..a633c55bf1be6 100644 --- a/test/LiteralExpressions/VisibilityRestriction.swift +++ b/test/LiteralExpressions/VisibilityRestriction.swift @@ -1,10 +1,8 @@ // Literal expressions may not reference `let` bindings that are part of the // module's ABI surface: publicly visible bindings, or `@usableFromInline` ones. -// REQUIRES: swift_feature_LiteralExpressions // RUN: %target-swift-frontend -typecheck %s -verify \ // RUN: -package-name myPkg \ -// RUN: -disable-availability-checking \ -// RUN: -enable-experimental-feature LiteralExpressions +// RUN: -disable-availability-checking public let publicPageSize = 4096 package let packagePageSize = 4096