From bad48874f0ae987462c7abbe68156a89cbaaa9d8 Mon Sep 17 00:00:00 2001 From: Cal Stephens Date: Mon, 19 May 2025 09:03:11 -0700 Subject: [PATCH 1/3] Add trailing comma support in cases missing from Swift 6.1 --- lib/Parse/ParseDecl.cpp | 26 +++++++++++++++---- lib/Parse/ParseStmt.cpp | 4 +-- lib/Parse/ParseType.cpp | 8 ++++-- test/ASTGen/availability.swift | 27 ++++++++++++++++++++ test/ASTGen/macros.swift | 24 +++++++++++++++-- test/Casting/ParameterizedExistentials.swift | 5 +++- test/Parse/availability_query.swift | 2 +- test/Parse/trailing-comma.swift | 12 ++++----- test/attr/Inputs/SymbolMove/LowLevel.swift | 12 +++++++-- test/attr/attr_availability_noasync.swift | 10 ++++++++ test/attr/attr_availability_watchos.swift | 8 ++++-- test/attr/attr_backDeployed.swift | 8 +++--- test/attr/attr_inlinable_available.swift | 7 +++-- test/decl/ext/typealias.swift | 10 ++++++++ test/decl/var/init_accessors.swift | 5 +++- test/type/types.swift | 13 ++++++++++ 16 files changed, 151 insertions(+), 30 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 006c0477215eb..60bd9095bca12 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -535,6 +535,11 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( // Parse the trailing comma if (consumeIf(tok::comma)) { HasUpcomingEntry = true; + + // If this is a trailing comma then there are no more entries + if (Tok.is(tok::r_paren)) { + break; + } } else { HasUpcomingEntry = false; } @@ -1008,6 +1013,11 @@ Parser::parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc) { // Parse the comma, if the list continues. hasNextProperty = consumeIf(tok::comma); + + // If this was a trailing comma, the list is complete. + if (Tok.is(tok::r_paren)) { + break; + } } while (hasNextProperty); return status; @@ -2015,7 +2025,7 @@ bool Parser::parseBackDeployedAttribute(DeclAttributes &Attributes, do { Result = parseListItem( Status, tok::r_paren, LeftLoc, RightLoc, - /*AllowSepAfterLast=*/false, [&]() -> ParserStatus { + /*AllowSepAfterLast=*/true, [&]() -> ParserStatus { return parsePlatformVersionInList(AtAttrName, PlatformAndVersions, ParsedUnrecognizedPlatformName); }); @@ -2137,7 +2147,7 @@ Parser::parseAttributeArguments(SourceLoc attrLoc, StringRef attrName, } return parseList(tok::r_paren, parensRange.Start, parensRange.End, - /*allow sep after last*/ true, + /*AllowSepAfterLast=*/true, {diag::attr_expected_rparen, {attrName, isModifier}}, parseArg); } @@ -2257,7 +2267,7 @@ Parser::parseMacroRoleAttribute( SmallVector conformances; auto argumentsStatus = parseList( tok::r_paren, lParenLoc, rParenLoc, - /*AllowSepAfterLast=*/false, diag::expected_rparen_expr_list, [&] { + /*AllowSepAfterLast=*/true, diag::expected_rparen_expr_list, [&] { ParserStatus status; if (consumeIf(tok::code_complete)) { @@ -3243,7 +3253,8 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, StringRef AttrName = "@_originallyDefinedIn"; bool SuppressLaterDiags = false; bool ParsedUnrecognizedPlatformName = false; - if (parseList(tok::r_paren, LeftLoc, RightLoc, false, + if (parseList(tok::r_paren, LeftLoc, RightLoc, + /*AllowSepAfterLast=*/true, diag::originally_defined_in_missing_rparen, [&]() -> ParserStatus { SWIFT_DEFER { @@ -4976,7 +4987,7 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { SourceLoc rParenLoc; bool foundParamId = false; status = parseList( - tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast*/ false, + tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast=*/true, diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { ParserStatus listStatus; foundParamId = true; @@ -9525,6 +9536,11 @@ ParserStatus Parser::parsePrimaryAssociatedTypeList( // Parse the comma, if the list continues. HasNextParam = consumeIf(tok::comma); + + // The list ends if we find a trailing comma + if (startsWithGreater(Tok)) { + break; + } } while (HasNextParam); return Result; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 45d0f59112105..6b948acd31979 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1445,8 +1445,8 @@ Parser::parseAvailabilitySpecList(SmallVectorImpl &Specs, consumeToken(); Status.setIsParseError(); } else if (consumeIf(tok::comma)) { - // End of unavailable spec list with a trailing comma. - if (Source == AvailabilitySpecSource::Unavailable && Tok.is(tok::r_paren)) { + // End of spec list with a trailing comma. + if (Tok.is(tok::r_paren)) { break; } // There is more to parse in this list. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 18cfad4d45e5e..9714b6a144d69 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -194,7 +194,7 @@ ParserResult Parser::parseTypeSimple( SourceLoc rbLoc; SmallVector elements; auto status = parseList(tok::r_brace, lbLoc, rbLoc, - /*AllowSepAfterLast=*/false, + /*AllowSepAfterLast=*/true, diag::expected_rbrace_pack_type_list, [&] () -> ParserStatus { auto element = parseType(diag::expected_type); @@ -742,6 +742,10 @@ ParserStatus Parser::parseGenericArguments(SmallVectorImpl &Args, // Parse the comma, if the list continues. if (!consumeIf(tok::comma)) break; + + // If the comma was a trailing comma, finish parsing the list of types + if (startsWithGreater(Tok)) + break; } } @@ -1161,7 +1165,7 @@ ParserResult Parser::parseTypeTupleBody() { SmallVector ElementsR; ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc, - /*AllowSepAfterLast=*/false, + /*AllowSepAfterLast=*/true, diag::expected_rparen_tuple_type_list, [&] () -> ParserStatus { TupleTypeReprElement element; diff --git a/test/ASTGen/availability.swift b/test/ASTGen/availability.swift index 72077ec6a6c60..dcc2f65ca7f8a 100644 --- a/test/ASTGen/availability.swift +++ b/test/ASTGen/availability.swift @@ -30,12 +30,22 @@ func testSwift4OrLater() {} @available(macOS 12, iOS 13.1, *) func testShorthandMulti() {} +@available(macOS 12, iOS 13.1, *,) +func testShorthandMulti2() {} + @available(macOS, unavailable) func testUnavailableMacOS() {} @available(macOS, deprecated: 12.0.5, message: "whatever") func testDeprecaed12MacOS() {} +@available( + macOS, + deprecated: 12.0.5, + message: "whatever", +) +func testDeprecaed12MacOS2() {} + @available(_iOS53Aligned, *) func testMacroNameOnly() {} @@ -48,10 +58,27 @@ func testSpecialize(arg: T) -> T {} @backDeployed(before: _iOS53Aligned) public func testBackDeployed() {} +@backDeployed( + before: _iOS53Aligned, +) +public func testBackDeployed2() {} + @available(macOS 10, iOS 12, *) @_originallyDefinedIn(module: "OriginalModule", macOS 12.0, iOS 23.2) public func testOriginallyDefinedIn() {} +@available( + macOS 10, + iOS 12, + *, +) +@_originallyDefinedIn( + module: "OriginalModule", + macOS 12.0, + iOS 23.2, +) +public func testOriginallyDefinedIn2() {} + func testPoundIf() { if #available(_myProject 2.5, *) { diff --git a/test/ASTGen/macros.swift b/test/ASTGen/macros.swift index 99f5f181f4270..169a85ee18570 100644 --- a/test/ASTGen/macros.swift +++ b/test/ASTGen/macros.swift @@ -18,7 +18,10 @@ struct Outer { #anonymousTypes { "test" } } -@attached(extension, conformances: P1, P2) +@attached( + extension, + conformances: P1, P2, +) macro AddAllConformances() = #externalMacro(module: "MacroDefinition", type: "AddAllConformancesMacro") protocol P1 {} @@ -39,6 +42,13 @@ protocol DefaultInit { @attached(extension, conformances: Equatable, names: named(==)) macro Equatable() = #externalMacro(module: "MacroDefinition", type: "EquatableViaMembersMacro") +@attached( + extension, + conformances: Equatable, + names: named(==), +) +macro Equatable2() = #externalMacro(module: "MacroDefinition", type: "EquatableViaMembersMacro") + @propertyWrapper struct NotEquatable { var wrappedValue: T @@ -112,10 +122,17 @@ func remoteCall(function: String, arguments: [String func f(a: Int, b: String) async throws -> String @freestanding(declaration, names: arbitrary) macro bitwidthNumberedStructs(_ baseName: String) = #externalMacro(module: "MacroDefinition", type: "DefineBitwidthNumberedStructsMacro") + struct TestArbitrary { #bitwidthNumberedStructs("MyIntOne") } +@freestanding( + declaration, + names: arbitrary, +) +macro bitwidthNumberedStructs2(_ baseName: String) = #externalMacro(module: "MacroDefinition", type: "DefineBitwidthNumberedStructsMacro") + // Stored properties generated by a peer macro @attached(accessor) @attached(peer, names: prefixed(_)) @@ -151,5 +168,8 @@ protocol MyType { associatedtype Value associatedtype Entity } -@attached(peer, names: named(bar)) +@attached( + peer, + names: named(bar), +) macro Wrapper(get: (Value.Entity) async throws -> Value.Value) = #externalMacro(module: "MacroDefinition", type: "WrapperMacro") where Value: MyType diff --git a/test/Casting/ParameterizedExistentials.swift b/test/Casting/ParameterizedExistentials.swift index ea893d7c02912..c6fd92d30c49f 100644 --- a/test/Casting/ParameterizedExistentials.swift +++ b/test/Casting/ParameterizedExistentials.swift @@ -46,7 +46,10 @@ struct GenericHolder: Holder { init(value: T) { self.value = value} } -protocol PairType { +protocol PairType< + T, + U, +> { associatedtype T associatedtype U diff --git a/test/Parse/availability_query.swift b/test/Parse/availability_query.swift index ae2a58e7662f8..3f543a53ad1b5 100644 --- a/test/Parse/availability_query.swift +++ b/test/Parse/availability_query.swift @@ -94,7 +94,7 @@ if #available(OSX 51, iOS 8.0, *) { if #available(OSX 51, { // expected-error {{expected platform name}} // expected-error {{expected ')'}} expected-note {{to match this opening '('}} } -if #available(OSX 51,) { // expected-error {{expected platform name}} +if #available(OSX 51,) { // expected-error {{must handle potential future platforms with '*'}} } if #available(OSX 51, iOS { // expected-error {{expected ')'}} expected-note {{to match this opening '('}} diff --git a/test/Parse/trailing-comma.swift b/test/Parse/trailing-comma.swift index 200733e8885e1..c680c8aa26d4b 100644 --- a/test/Parse/trailing-comma.swift +++ b/test/Parse/trailing-comma.swift @@ -66,20 +66,20 @@ struct S { if #unavailable(iOS 15, watchOS 9,) { } -if #available(iOS 15,) { } // expected-error {{expected platform name}} +if #available(iOS 15,) { } // Built-in Attributes -@attached(extension, conformances: OptionSet,) // expected-error {{unexpected ',' separator}} +@attached(extension, conformances: OptionSet,) macro OptionSet() = #externalMacro(module: "SwiftMacros", type: "OptionSetMacro") @inline(never,) // expected-error {{expected declaration}} expected-error {{expected ')' in 'inline' attribute}} func foo() { } -@available(iOS 15,) // expected-error {{expected platform name}} expected-error {{expected declaration}} +@available(iOS 15,) func foo() { } -@backDeployed(before: SwiftStdlib 6.0,) // expected-error {{unexpected ',' separator}} +@backDeployed(before: SwiftStdlib 6.0,) func foo() { } struct Foo { @@ -88,7 +88,7 @@ struct Foo { var y: Int var value: (Int, Int) { - @storageRestrictions(initializes: x, y,) // expected-error {{expected property name in '@storageRestrictions' list}} + @storageRestrictions(initializes: x, y,) init(initialValue) { self.x = initialValue.0 self.y = initialValue.1 @@ -98,7 +98,7 @@ struct Foo { } -func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{unexpected ',' separator}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} +func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} @derivative(of: Self.other,) // expected-error {{unexpected ',' separator}} func foo() {} diff --git a/test/attr/Inputs/SymbolMove/LowLevel.swift b/test/attr/Inputs/SymbolMove/LowLevel.swift index 5168a409baab9..7a877fa0aace6 100644 --- a/test/attr/Inputs/SymbolMove/LowLevel.swift +++ b/test/attr/Inputs/SymbolMove/LowLevel.swift @@ -30,8 +30,16 @@ extension Box { public func shape() -> String { return "round"} } -@available(OSX 10.7, iOS 7.0, *) -@_originallyDefinedIn(module: "HighLevel", OSX 10.9, iOS 13.0) +@available( + OSX 10.7, + iOS 7.0, + *, +) +@_originallyDefinedIn( + module: "HighLevel", + OSX 10.9, + iOS 13.0, +) public struct Candy { public var kind = "candy" public init() {} diff --git a/test/attr/attr_availability_noasync.swift b/test/attr/attr_availability_noasync.swift index 9fb5be3dee95c..cd60bab02f90f 100644 --- a/test/attr/attr_availability_noasync.swift +++ b/test/attr/attr_availability_noasync.swift @@ -6,9 +6,19 @@ @available(*, noasync) func basicNoAsync() { } +@available(*, noasync,) +func basicNoAsync2() { } + @available(*, noasync, message: "a message from the author") func messageNoAsync() { } +@available( + *, + noasync, + message: "a message from the author", +) +func messageNoAsync2() { } + @available(*, noasync, renamed: "asyncReplacement()") func renamedNoAsync(_ completion: @escaping (Int) -> Void) -> Void { } diff --git a/test/attr/attr_availability_watchos.swift b/test/attr/attr_availability_watchos.swift index 0a632d12d054d..60dbf8d3388ad 100644 --- a/test/attr/attr_availability_watchos.swift +++ b/test/attr/attr_availability_watchos.swift @@ -58,8 +58,12 @@ if #available(iOS 9.3, *) { // expected-note@-1 {{add 'if #available' version check}} } -if #available(iOS 9.3, watchOS 2.1, *) { - functionIntroducedOnwatchOS2_2() // expected-error {{'functionIntroducedOnwatchOS2_2()' is only available in watchOS 2.2 or newer}} {{-1:32-35=2.2}} +if #available( + iOS 9.3, + watchOS 2.1, + *, +) { + functionIntroducedOnwatchOS2_2() // expected-error {{'functionIntroducedOnwatchOS2_2()' is only available in watchOS 2.2 or newer}} {{63:11-14=2.2}} } if #available(iOS 9.1, watchOS 2.2, *) { diff --git a/test/attr/attr_backDeployed.swift b/test/attr/attr_backDeployed.swift index d1f051f5cc742..a30c3b5083457 100644 --- a/test/attr/attr_backDeployed.swift +++ b/test/attr/attr_backDeployed.swift @@ -394,8 +394,8 @@ public func missingVersionFunc3() {} @backDeployed(before: macOS 0) // expected-warning {{expected version number in '@backDeployed' attribute; this is an error in the Swift 6 language mode}} public func missingVersionFunc4() {} -@backDeployed(before: macOS 12.0, iOS 15.0,) // expected-error {{unexpected ',' separator}} -public func unexpectedSeparatorFunc() {} +@backDeployed(before: macOS 12.0, iOS 15.0,) +public func trailingCommaFunc1() {} @backDeployed(before: macOS 12.0.1) // expected-warning {{'@backDeployed' only uses major and minor version number}} public func patchVersionFunc() {} @@ -440,8 +440,8 @@ public func missingColonAfterBeforeFunc() {} @backDeployed(before macOS 12.0) // expected-error {{expected ':' after 'before' in '@backDeployed' attribute}} {{21-21=:}} public func missingColonBetweenBeforeAndPlatformFunc() {} -@backDeployed(before: macOS 12.0,) // expected-error {{unexpected ',' separator}} {{33-34=}} -public func unexpectedTrailingCommaFunc() {} +@backDeployed(before: macOS 12.0,) +public func trailingCommaFunc2() {} @backDeployed(before: macOS 12.0,, iOS 15.0) // expected-error {{unexpected ',' separator}} {{34-35=}} public func extraCommaFunc() {} diff --git a/test/attr/attr_inlinable_available.swift b/test/attr/attr_inlinable_available.swift index e5e437698be12..5e6713c3d07f1 100644 --- a/test/attr/attr_inlinable_available.swift +++ b/test/attr/attr_inlinable_available.swift @@ -530,7 +530,10 @@ public func spiDeployedUseNoAvailable( // expected-note 3 {{add '@available' att _ = AtDeploymentTarget() _ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note {{add 'if #available'}} - if #available(macOS 11, *) { + if #available( + macOS 11, + *, + ) { _ = AfterDeploymentTarget() } } @@ -720,7 +723,7 @@ public func spiDeployedUseNoAvailable( // expected-note 3 {{add '@available' att _ = AtDeploymentTarget() _ = AfterDeploymentTarget() - if #available(macOS 11, *) { + if #available(macOS 11, *,) { _ = AfterDeploymentTarget() } diff --git a/test/decl/ext/typealias.swift b/test/decl/ext/typealias.swift index c5917a0a0d565..cc99ee12d7846 100644 --- a/test/decl/ext/typealias.swift +++ b/test/decl/ext/typealias.swift @@ -78,3 +78,13 @@ extension FooIntBarFloatDoubleInner { } } +struct Foo2 {} + +typealias Bar2< + T1, + T2, +> = Foo2< + T1, + T2, + Bool, +> diff --git a/test/decl/var/init_accessors.swift b/test/decl/var/init_accessors.swift index 0646d9be38ada..10c76c9572858 100644 --- a/test/decl/var/init_accessors.swift +++ b/test/decl/var/init_accessors.swift @@ -45,7 +45,10 @@ func test_use_of_initializes_accesses_on_non_inits() { var y: String var _x: Int { - @storageRestrictions(initializes: x, accesses: y) + @storageRestrictions( + initializes: x, + accesses: y, + ) init(initialValue) { // Ok } diff --git a/test/type/types.swift b/test/type/types.swift index 09b217c147875..aeb5342ffaad8 100644 --- a/test/type/types.swift +++ b/test/type/types.swift @@ -219,3 +219,16 @@ do { subscript(_: inout Double...) -> Bool { true } // expected-error {{'inout' may only be used on function or initializer parameters}} } } + +let tupleTypeWithTrailingComma: ( + bar: String, + quux: String, +) + +let closureTypeWithTrailingCommas: ( + String, + String, +) -> ( + bar: String, + quux: String, +) From f4bedbc720f18502983eb17f69b531d4e25a74e6 Mon Sep 17 00:00:00 2001 From: Cal Stephens Date: Mon, 19 May 2025 15:55:44 -0700 Subject: [PATCH 2/3] Revert changes to trailing commas in attributes like @available --- lib/Parse/ParseDecl.cpp | 18 ++++---------- lib/Parse/ParseStmt.cpp | 4 ++-- lib/Parse/ParseType.cpp | 2 +- test/ASTGen/availability.swift | 27 --------------------- test/ASTGen/macros.swift | 24 ++----------------- test/Parse/availability_query.swift | 2 +- test/Parse/trailing-comma.swift | 28 +++++++++++++++------- test/attr/Inputs/SymbolMove/LowLevel.swift | 12 ++-------- test/attr/attr_availability_noasync.swift | 10 -------- test/attr/attr_availability_watchos.swift | 8 ++----- test/attr/attr_backDeployed.swift | 8 +++---- test/attr/attr_inlinable_available.swift | 7 ++---- test/decl/var/init_accessors.swift | 5 +--- 13 files changed, 41 insertions(+), 114 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 60bd9095bca12..c6e1776656047 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -535,11 +535,6 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( // Parse the trailing comma if (consumeIf(tok::comma)) { HasUpcomingEntry = true; - - // If this is a trailing comma then there are no more entries - if (Tok.is(tok::r_paren)) { - break; - } } else { HasUpcomingEntry = false; } @@ -1013,11 +1008,6 @@ Parser::parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc) { // Parse the comma, if the list continues. hasNextProperty = consumeIf(tok::comma); - - // If this was a trailing comma, the list is complete. - if (Tok.is(tok::r_paren)) { - break; - } } while (hasNextProperty); return status; @@ -2025,7 +2015,7 @@ bool Parser::parseBackDeployedAttribute(DeclAttributes &Attributes, do { Result = parseListItem( Status, tok::r_paren, LeftLoc, RightLoc, - /*AllowSepAfterLast=*/true, [&]() -> ParserStatus { + /*AllowSepAfterLast=*/false, [&]() -> ParserStatus { return parsePlatformVersionInList(AtAttrName, PlatformAndVersions, ParsedUnrecognizedPlatformName); }); @@ -2267,7 +2257,7 @@ Parser::parseMacroRoleAttribute( SmallVector conformances; auto argumentsStatus = parseList( tok::r_paren, lParenLoc, rParenLoc, - /*AllowSepAfterLast=*/true, diag::expected_rparen_expr_list, [&] { + /*AllowSepAfterLast=*/false, diag::expected_rparen_expr_list, [&] { ParserStatus status; if (consumeIf(tok::code_complete)) { @@ -3254,7 +3244,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, bool SuppressLaterDiags = false; bool ParsedUnrecognizedPlatformName = false; if (parseList(tok::r_paren, LeftLoc, RightLoc, - /*AllowSepAfterLast=*/true, + /*AllowSepAfterLast=*/false, diag::originally_defined_in_missing_rparen, [&]() -> ParserStatus { SWIFT_DEFER { @@ -4987,7 +4977,7 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { SourceLoc rParenLoc; bool foundParamId = false; status = parseList( - tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast=*/true, + tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast=*/false, diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { ParserStatus listStatus; foundParamId = true; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 6b948acd31979..45d0f59112105 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1445,8 +1445,8 @@ Parser::parseAvailabilitySpecList(SmallVectorImpl &Specs, consumeToken(); Status.setIsParseError(); } else if (consumeIf(tok::comma)) { - // End of spec list with a trailing comma. - if (Tok.is(tok::r_paren)) { + // End of unavailable spec list with a trailing comma. + if (Source == AvailabilitySpecSource::Unavailable && Tok.is(tok::r_paren)) { break; } // There is more to parse in this list. diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 9714b6a144d69..811552941cc5f 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -194,7 +194,7 @@ ParserResult Parser::parseTypeSimple( SourceLoc rbLoc; SmallVector elements; auto status = parseList(tok::r_brace, lbLoc, rbLoc, - /*AllowSepAfterLast=*/true, + /*AllowSepAfterLast=*/false, diag::expected_rbrace_pack_type_list, [&] () -> ParserStatus { auto element = parseType(diag::expected_type); diff --git a/test/ASTGen/availability.swift b/test/ASTGen/availability.swift index dcc2f65ca7f8a..72077ec6a6c60 100644 --- a/test/ASTGen/availability.swift +++ b/test/ASTGen/availability.swift @@ -30,22 +30,12 @@ func testSwift4OrLater() {} @available(macOS 12, iOS 13.1, *) func testShorthandMulti() {} -@available(macOS 12, iOS 13.1, *,) -func testShorthandMulti2() {} - @available(macOS, unavailable) func testUnavailableMacOS() {} @available(macOS, deprecated: 12.0.5, message: "whatever") func testDeprecaed12MacOS() {} -@available( - macOS, - deprecated: 12.0.5, - message: "whatever", -) -func testDeprecaed12MacOS2() {} - @available(_iOS53Aligned, *) func testMacroNameOnly() {} @@ -58,27 +48,10 @@ func testSpecialize(arg: T) -> T {} @backDeployed(before: _iOS53Aligned) public func testBackDeployed() {} -@backDeployed( - before: _iOS53Aligned, -) -public func testBackDeployed2() {} - @available(macOS 10, iOS 12, *) @_originallyDefinedIn(module: "OriginalModule", macOS 12.0, iOS 23.2) public func testOriginallyDefinedIn() {} -@available( - macOS 10, - iOS 12, - *, -) -@_originallyDefinedIn( - module: "OriginalModule", - macOS 12.0, - iOS 23.2, -) -public func testOriginallyDefinedIn2() {} - func testPoundIf() { if #available(_myProject 2.5, *) { diff --git a/test/ASTGen/macros.swift b/test/ASTGen/macros.swift index 169a85ee18570..99f5f181f4270 100644 --- a/test/ASTGen/macros.swift +++ b/test/ASTGen/macros.swift @@ -18,10 +18,7 @@ struct Outer { #anonymousTypes { "test" } } -@attached( - extension, - conformances: P1, P2, -) +@attached(extension, conformances: P1, P2) macro AddAllConformances() = #externalMacro(module: "MacroDefinition", type: "AddAllConformancesMacro") protocol P1 {} @@ -42,13 +39,6 @@ protocol DefaultInit { @attached(extension, conformances: Equatable, names: named(==)) macro Equatable() = #externalMacro(module: "MacroDefinition", type: "EquatableViaMembersMacro") -@attached( - extension, - conformances: Equatable, - names: named(==), -) -macro Equatable2() = #externalMacro(module: "MacroDefinition", type: "EquatableViaMembersMacro") - @propertyWrapper struct NotEquatable { var wrappedValue: T @@ -122,17 +112,10 @@ func remoteCall(function: String, arguments: [String func f(a: Int, b: String) async throws -> String @freestanding(declaration, names: arbitrary) macro bitwidthNumberedStructs(_ baseName: String) = #externalMacro(module: "MacroDefinition", type: "DefineBitwidthNumberedStructsMacro") - struct TestArbitrary { #bitwidthNumberedStructs("MyIntOne") } -@freestanding( - declaration, - names: arbitrary, -) -macro bitwidthNumberedStructs2(_ baseName: String) = #externalMacro(module: "MacroDefinition", type: "DefineBitwidthNumberedStructsMacro") - // Stored properties generated by a peer macro @attached(accessor) @attached(peer, names: prefixed(_)) @@ -168,8 +151,5 @@ protocol MyType { associatedtype Value associatedtype Entity } -@attached( - peer, - names: named(bar), -) +@attached(peer, names: named(bar)) macro Wrapper(get: (Value.Entity) async throws -> Value.Value) = #externalMacro(module: "MacroDefinition", type: "WrapperMacro") where Value: MyType diff --git a/test/Parse/availability_query.swift b/test/Parse/availability_query.swift index 3f543a53ad1b5..ae2a58e7662f8 100644 --- a/test/Parse/availability_query.swift +++ b/test/Parse/availability_query.swift @@ -94,7 +94,7 @@ if #available(OSX 51, iOS 8.0, *) { if #available(OSX 51, { // expected-error {{expected platform name}} // expected-error {{expected ')'}} expected-note {{to match this opening '('}} } -if #available(OSX 51,) { // expected-error {{must handle potential future platforms with '*'}} +if #available(OSX 51,) { // expected-error {{expected platform name}} } if #available(OSX 51, iOS { // expected-error {{expected ')'}} expected-note {{to match this opening '('}} diff --git a/test/Parse/trailing-comma.swift b/test/Parse/trailing-comma.swift index c680c8aa26d4b..73c7154edf6dd 100644 --- a/test/Parse/trailing-comma.swift +++ b/test/Parse/trailing-comma.swift @@ -9,6 +9,10 @@ let values: [Int,] = [] // expected-note {{to match this opening '['}} expected- // Tuple and Tuple Pattern let _ = (a: 1, b: 2, c: 3,) +let _: (a: Int, b: Int, c: Int,) = (a: 1, b: 2, c: 3,) + +// Closures +let _: (String, Int, Float,) -> Void let (_, _,) = (0,1,) @@ -34,7 +38,7 @@ struct S { } func foo() { } -protocol P { +protocol P { associatedtype T1 associatedtype T2 } @@ -66,20 +70,20 @@ struct S { if #unavailable(iOS 15, watchOS 9,) { } -if #available(iOS 15,) { } +if #available(iOS 15,) { } // expected-error {{expected platform name}} // Built-in Attributes -@attached(extension, conformances: OptionSet,) +@attached(extension, conformances: OptionSet,) // expected-error {{unexpected ',' separator}} macro OptionSet() = #externalMacro(module: "SwiftMacros", type: "OptionSetMacro") @inline(never,) // expected-error {{expected declaration}} expected-error {{expected ')' in 'inline' attribute}} func foo() { } -@available(iOS 15,) +@available(iOS 15,) // expected-error {{expected platform name}} expected-error {{expected declaration}} func foo() { } -@backDeployed(before: SwiftStdlib 6.0,) +@backDeployed(before: SwiftStdlib 6.0,) // expected-error {{unexpected ',' separator}} func foo() { } struct Foo { @@ -88,7 +92,7 @@ struct Foo { var y: Int var value: (Int, Int) { - @storageRestrictions(initializes: x, y,) + @storageRestrictions(initializes: x, y,) // expected-error {{expected property name in '@storageRestrictions' list}} init(initialValue) { self.x = initialValue.0 self.y = initialValue.1 @@ -98,7 +102,7 @@ struct Foo { } -func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} +func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{unexpected ',' separator}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} @derivative(of: Self.other,) // expected-error {{unexpected ',' separator}} func foo() {} @@ -135,4 +139,12 @@ if true, { } // expected-error {{expected '{' after 'if' condition}} guard true, else { } // expected-error {{expected expression in conditional}} -while true, { } // expected-error {{expected '{' after 'while' condition}} \ No newline at end of file +while true, { } // expected-error {{expected '{' after 'while' condition}} + +if #available(OSX 51,) { // expected-error {{expected platform name}} +} + +@available(OSX 10.7, iOS 7.0, *,) // expected-error {{expected platform name}} +@_originallyDefinedIn(module: "HighLevel", OSX 10.9, iOS 13.0,) // expected-error {{unexpected ',' separator}} +@backDeployed(before: OSX 10.9,) // expected-error {{expected version number in '@backDeployed' attribute}} +public struct StructWithAvailability {} diff --git a/test/attr/Inputs/SymbolMove/LowLevel.swift b/test/attr/Inputs/SymbolMove/LowLevel.swift index 7a877fa0aace6..5168a409baab9 100644 --- a/test/attr/Inputs/SymbolMove/LowLevel.swift +++ b/test/attr/Inputs/SymbolMove/LowLevel.swift @@ -30,16 +30,8 @@ extension Box { public func shape() -> String { return "round"} } -@available( - OSX 10.7, - iOS 7.0, - *, -) -@_originallyDefinedIn( - module: "HighLevel", - OSX 10.9, - iOS 13.0, -) +@available(OSX 10.7, iOS 7.0, *) +@_originallyDefinedIn(module: "HighLevel", OSX 10.9, iOS 13.0) public struct Candy { public var kind = "candy" public init() {} diff --git a/test/attr/attr_availability_noasync.swift b/test/attr/attr_availability_noasync.swift index cd60bab02f90f..9fb5be3dee95c 100644 --- a/test/attr/attr_availability_noasync.swift +++ b/test/attr/attr_availability_noasync.swift @@ -6,19 +6,9 @@ @available(*, noasync) func basicNoAsync() { } -@available(*, noasync,) -func basicNoAsync2() { } - @available(*, noasync, message: "a message from the author") func messageNoAsync() { } -@available( - *, - noasync, - message: "a message from the author", -) -func messageNoAsync2() { } - @available(*, noasync, renamed: "asyncReplacement()") func renamedNoAsync(_ completion: @escaping (Int) -> Void) -> Void { } diff --git a/test/attr/attr_availability_watchos.swift b/test/attr/attr_availability_watchos.swift index 60dbf8d3388ad..0a632d12d054d 100644 --- a/test/attr/attr_availability_watchos.swift +++ b/test/attr/attr_availability_watchos.swift @@ -58,12 +58,8 @@ if #available(iOS 9.3, *) { // expected-note@-1 {{add 'if #available' version check}} } -if #available( - iOS 9.3, - watchOS 2.1, - *, -) { - functionIntroducedOnwatchOS2_2() // expected-error {{'functionIntroducedOnwatchOS2_2()' is only available in watchOS 2.2 or newer}} {{63:11-14=2.2}} +if #available(iOS 9.3, watchOS 2.1, *) { + functionIntroducedOnwatchOS2_2() // expected-error {{'functionIntroducedOnwatchOS2_2()' is only available in watchOS 2.2 or newer}} {{-1:32-35=2.2}} } if #available(iOS 9.1, watchOS 2.2, *) { diff --git a/test/attr/attr_backDeployed.swift b/test/attr/attr_backDeployed.swift index a30c3b5083457..d1f051f5cc742 100644 --- a/test/attr/attr_backDeployed.swift +++ b/test/attr/attr_backDeployed.swift @@ -394,8 +394,8 @@ public func missingVersionFunc3() {} @backDeployed(before: macOS 0) // expected-warning {{expected version number in '@backDeployed' attribute; this is an error in the Swift 6 language mode}} public func missingVersionFunc4() {} -@backDeployed(before: macOS 12.0, iOS 15.0,) -public func trailingCommaFunc1() {} +@backDeployed(before: macOS 12.0, iOS 15.0,) // expected-error {{unexpected ',' separator}} +public func unexpectedSeparatorFunc() {} @backDeployed(before: macOS 12.0.1) // expected-warning {{'@backDeployed' only uses major and minor version number}} public func patchVersionFunc() {} @@ -440,8 +440,8 @@ public func missingColonAfterBeforeFunc() {} @backDeployed(before macOS 12.0) // expected-error {{expected ':' after 'before' in '@backDeployed' attribute}} {{21-21=:}} public func missingColonBetweenBeforeAndPlatformFunc() {} -@backDeployed(before: macOS 12.0,) -public func trailingCommaFunc2() {} +@backDeployed(before: macOS 12.0,) // expected-error {{unexpected ',' separator}} {{33-34=}} +public func unexpectedTrailingCommaFunc() {} @backDeployed(before: macOS 12.0,, iOS 15.0) // expected-error {{unexpected ',' separator}} {{34-35=}} public func extraCommaFunc() {} diff --git a/test/attr/attr_inlinable_available.swift b/test/attr/attr_inlinable_available.swift index 5e6713c3d07f1..e5e437698be12 100644 --- a/test/attr/attr_inlinable_available.swift +++ b/test/attr/attr_inlinable_available.swift @@ -530,10 +530,7 @@ public func spiDeployedUseNoAvailable( // expected-note 3 {{add '@available' att _ = AtDeploymentTarget() _ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note {{add 'if #available'}} - if #available( - macOS 11, - *, - ) { + if #available(macOS 11, *) { _ = AfterDeploymentTarget() } } @@ -723,7 +720,7 @@ public func spiDeployedUseNoAvailable( // expected-note 3 {{add '@available' att _ = AtDeploymentTarget() _ = AfterDeploymentTarget() - if #available(macOS 11, *,) { + if #available(macOS 11, *) { _ = AfterDeploymentTarget() } diff --git a/test/decl/var/init_accessors.swift b/test/decl/var/init_accessors.swift index 10c76c9572858..0646d9be38ada 100644 --- a/test/decl/var/init_accessors.swift +++ b/test/decl/var/init_accessors.swift @@ -45,10 +45,7 @@ func test_use_of_initializes_accesses_on_non_inits() { var y: String var _x: Int { - @storageRestrictions( - initializes: x, - accesses: y, - ) + @storageRestrictions(initializes: x, accesses: y) init(initialValue) { // Ok } From e73beb435ea5133d83a9740beee225eb2937fd65 Mon Sep 17 00:00:00 2001 From: Cal Stephens Date: Mon, 19 May 2025 18:36:58 -0700 Subject: [PATCH 3/3] Support trailing commas in types within expressions --- lib/Parse/ParseType.cpp | 3 ++- test/Parse/trailing-comma.swift | 6 +++--- test/decl/ext/typealias.swift | 3 +++ test/type/types.swift | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 811552941cc5f..a66aed29cc3cd 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1609,7 +1609,8 @@ bool Parser::canParseGenericArguments() { if (!canParseType()) return false; // Parse the comma, if the list continues. - } while (consumeIf(tok::comma)); + // This could be the trailing comma. + } while (consumeIf(tok::comma) && !startsWithGreater(Tok)); if (!startsWithGreater(Tok)) { return false; diff --git a/test/Parse/trailing-comma.swift b/test/Parse/trailing-comma.swift index 73c7154edf6dd..453c3388f9eaa 100644 --- a/test/Parse/trailing-comma.swift +++ b/test/Parse/trailing-comma.swift @@ -102,7 +102,7 @@ struct Foo { } -func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{unexpected ',' separator}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} +func f(in: @differentiable(reverse,) (Int) -> Int) { } // expected-warning {{@differentiable' has been renamed to '@differentiable(reverse)' and will be removed in the next release}} expected-error {{expected ',' separator}} expected-error {{unnamed parameters must be written with the empty name '_'}} @derivative(of: Self.other,) // expected-error {{unexpected ',' separator}} func foo() {} @@ -144,7 +144,7 @@ while true, { } // expected-error {{expected '{' after 'while' condition}} if #available(OSX 51,) { // expected-error {{expected platform name}} } -@available(OSX 10.7, iOS 7.0, *,) // expected-error {{expected platform name}} +@available(OSX 10.7, iOS 7.0, *,) // expected-error {{expected platform name}} expected-error {{expected declaration}} @_originallyDefinedIn(module: "HighLevel", OSX 10.9, iOS 13.0,) // expected-error {{unexpected ',' separator}} -@backDeployed(before: OSX 10.9,) // expected-error {{expected version number in '@backDeployed' attribute}} +@backDeployed(before: OSX 10.9,) // expected-error {{unexpected ',' separator}} public struct StructWithAvailability {} diff --git a/test/decl/ext/typealias.swift b/test/decl/ext/typealias.swift index cc99ee12d7846..3d33655f7a80b 100644 --- a/test/decl/ext/typealias.swift +++ b/test/decl/ext/typealias.swift @@ -88,3 +88,6 @@ typealias Bar2< T2, Bool, > + +let _ = Foo2.self +let _ = Bar2() diff --git a/test/type/types.swift b/test/type/types.swift index aeb5342ffaad8..7176d1298c0f5 100644 --- a/test/type/types.swift +++ b/test/type/types.swift @@ -225,6 +225,8 @@ let tupleTypeWithTrailingComma: ( quux: String, ) +let _ = (bar: String, quux: String,).self + let closureTypeWithTrailingCommas: ( String, String,