Add trailing comma support in cases missing from Swift 6.1

This commit is contained in:
Cal Stephens
2025-05-19 09:03:11 -07:00
parent 749e9ee090
commit 1a3d71cc53
16 changed files with 151 additions and 30 deletions

View File

@@ -535,6 +535,11 @@ ParserResult<AvailableAttr> 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<Expr *, 2> 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)) {
@@ -3245,7 +3255,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 {
@@ -4978,7 +4989,7 @@ ParserResult<LifetimeEntry> 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;
@@ -9524,6 +9535,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;

View File

@@ -1445,8 +1445,8 @@ Parser::parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &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.

View File

@@ -194,7 +194,7 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
SourceLoc rbLoc;
SmallVector<TypeRepr *, 8> 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<TypeRepr *> &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<TypeRepr> Parser::parseTypeTupleBody() {
SmallVector<TupleTypeReprElement, 8> ElementsR;
ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc,
/*AllowSepAfterLast=*/false,
/*AllowSepAfterLast=*/true,
diag::expected_rparen_tuple_type_list,
[&] () -> ParserStatus {
TupleTypeReprElement element;

View File

@@ -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<T>(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, *) {

View File

@@ -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<T> {
var wrappedValue: T
@@ -112,10 +122,17 @@ func remoteCall<Result: ConjureRemoteValue>(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<Value>(get: (Value.Entity) async throws -> Value.Value) = #externalMacro(module: "MacroDefinition", type: "WrapperMacro") where Value: MyType

View File

@@ -46,7 +46,10 @@ struct GenericHolder<T>: Holder {
init(value: T) { self.value = value}
}
protocol PairType<T, U> {
protocol PairType<
T,
U,
> {
associatedtype T
associatedtype U

View File

@@ -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 '('}}

View File

@@ -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<RawType>() = #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() {}

View File

@@ -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() {}

View File

@@ -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 { }

View File

@@ -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, *) {

View File

@@ -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() {}

View File

@@ -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()
}

View File

@@ -78,3 +78,13 @@ extension FooIntBarFloatDoubleInner {
}
}
struct Foo2<T1, T2, T3,> {}
typealias Bar2<
T1,
T2,
> = Foo2<
T1,
T2,
Bool,
>

View File

@@ -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
}

View File

@@ -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,
)