diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 5a1f4da04cc..4c66812bd7d 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -932,10 +932,19 @@ extension Parser { leadingExpr: RawExprSyntax, flavor: ExprFlavor ) -> RawExprSyntax? { - guard - self.at(.leftBrace) && !leadingExpr.raw.kind.isLiteral - && self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) - else { + guard self.at(.leftBrace) else { + return nil + } + + if leadingExpr.raw.kind.isLiteral { + // Trailing closures are allowed after array and dictionary types, + // since this can mean `[Element].init { }` or `[Key: Value].init { }`. + guard leadingExpr.raw.kind == .arrayExpr || leadingExpr.raw.kind == .dictionaryExpr else { + return nil + } + } + + guard self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) else { return nil } diff --git a/Tests/SwiftParserTest/ExpressionTests.swift b/Tests/SwiftParserTest/ExpressionTests.swift index 41ac9978167..2ec2a2dbc8d 100644 --- a/Tests/SwiftParserTest/ExpressionTests.swift +++ b/Tests/SwiftParserTest/ExpressionTests.swift @@ -87,6 +87,80 @@ final class ExpressionTests: ParserTestCase { assertParse("compactMap { (parserDiag) in }") } + func testCollectionTrailingClosureInits() { + assertParse( + "let value = 1️⃣[Foo] { bar }", + substructure: FunctionCallExprSyntax( + calledExpression: ArrayExprSyntax( + leftSquare: .leftSquareToken(), + elements: ArrayElementListSyntax([ + ArrayElementSyntax( + expression: DeclReferenceExprSyntax(baseName: .identifier("Foo")), + trailingComma: nil + ) + ]), + rightSquare: .rightSquareToken() + ), + leftParen: nil, + arguments: LabeledExprListSyntax([]), + rightParen: nil, + trailingClosure: ClosureExprSyntax( + leftBrace: .leftBraceToken(), + signature: nil, + statements: CodeBlockItemListSyntax([ + CodeBlockItemSyntax( + item: .expr( + ExprSyntax( + DeclReferenceExprSyntax(baseName: .identifier("bar")) + ) + ) + ) + ]), + rightBrace: .rightBraceToken() + ) + ), + substructureAfterMarker: "1️⃣" + ) + + assertParse( + "let value = 1️⃣[String: Int] { value }", + substructure: FunctionCallExprSyntax( + calledExpression: DictionaryExprSyntax( + leftSquare: .leftSquareToken(), + content: .elements( + DictionaryElementListSyntax([ + DictionaryElementSyntax( + key: DeclReferenceExprSyntax(baseName: .identifier("String")), + colon: .colonToken(), + value: DeclReferenceExprSyntax(baseName: .identifier("Int")), + trailingComma: nil + ) + ]) + ), + rightSquare: .rightSquareToken() + ), + leftParen: nil, + arguments: LabeledExprListSyntax([]), + rightParen: nil, + trailingClosure: ClosureExprSyntax( + leftBrace: .leftBraceToken(), + signature: nil, + statements: CodeBlockItemListSyntax([ + CodeBlockItemSyntax( + item: .expr( + ExprSyntax( + DeclReferenceExprSyntax(baseName: .identifier("value")) + ) + ) + ) + ]), + rightBrace: .rightBraceToken() + ) + ), + substructureAfterMarker: "1️⃣" + ) + } + func testSequenceExpressions() { assertParse("await a()") assertParse( @@ -2180,22 +2254,8 @@ final class ExpressionTests: ParserTestCase { { return /foo/ } """ ) - assertParse( - "_ = [1]1️⃣ { return [1] }", - diagnostics: expectedDiagnostics, - fixedSource: """ - _ = [1] - { return [1] } - """ - ) - assertParse( - "_ = [1: 1]1️⃣ { return [1: 1] }", - diagnostics: expectedDiagnostics, - fixedSource: """ - _ = [1: 1] - { return [1: 1] } - """ - ) + assertParse("_ = [1] { return [1] }") + assertParse("_ = [1: 1] { return [1: 1] }") assertParse( "_ = 1 + 11️⃣ { return 1 }",