Skip to content

Add trailing comma support in cases missing from Swift 6.1 #81612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2137,7 +2137,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);
}
Expand Down Expand Up @@ -3245,7 +3245,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=*/false,
diag::originally_defined_in_missing_rparen,
[&]() -> ParserStatus {
SWIFT_DEFER {
Expand Down Expand Up @@ -4978,7 +4979,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=*/false,
diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus {
ParserStatus listStatus;
foundParamId = true;
Expand Down Expand Up @@ -9524,6 +9525,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;
Expand Down
6 changes: 5 additions & 1 deletion lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion test/Casting/ParameterizedExistentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 14 additions & 2 deletions test/Parse/trailing-comma.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,)

Expand All @@ -34,7 +38,7 @@ struct S<T1, T2,> { }

func foo<T1, T2,>() { }

protocol P<T1, T2> {
protocol P<T1, T2,> {
associatedtype T1
associatedtype T2
}
Expand Down Expand Up @@ -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}}
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 {}
10 changes: 10 additions & 0 deletions test/decl/ext/typealias.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,13 @@ extension FooIntBarFloatDoubleInner {
}
}

struct Foo2<T1, T2, T3,> {}

typealias Bar2<
T1,
T2,
> = Foo2<
T1,
T2,
Bool,
>
Copy link
Member

@rintaro rintaro May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding test cases for generic arguments in expression positions to prevent future regressions? Like let _ = Generic<Int, Bool,>.self and let _ = Generic<Int, Bool,>(). It also uses parseGenericArguments() (currently) so it should work with your changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for remembering to check that! It didn't work originally, we also had to update the lookahead code that disambiguated the < between a generic list and a less than operator. Updated, working now :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah canParseGenericArguments(). That makes sense. Thank you for fixing it!

13 changes: 13 additions & 0 deletions test/type/types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)